src/platform/3ds/ctr-gpu.c (view raw)
1/* Copyright (c) 2015 Yuri Kunde Schlesner
2 * Copyright (c) 2016 Jeffrey Pfau
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8#include <3ds.h>
9#include <3ds/gpu/gpu.h>
10#include <3ds/gpu/gx.h>
11#include <stdlib.h>
12#include <string.h>
13#include <stdio.h>
14
15#include "ctr-gpu.h"
16
17#include "uishader_v.h"
18#include "uishader_v.shbin.h"
19#include "uishader_g.h"
20#include "uishader_g.shbin.h"
21
22struct ctrUIVertex {
23 short x, y;
24 short w, h;
25 short u, v;
26 short uw, vh;
27 u32 abgr;
28};
29
30#define MAX_NUM_QUADS 1024
31#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex)
32
33static struct ctrUIVertex* ctrVertexBuffer = NULL;
34static u16 ctrNumQuads = 0;
35
36static C3D_Tex* activeTexture = NULL;
37
38static shaderProgram_s gpuShader;
39static DVLB_s* vertexShader = NULL;
40static DVLB_s* geometryShader = NULL;
41
42bool ctrInitGpu() {
43 // Load vertex shader binary
44 vertexShader = DVLB_ParseFile((u32*) uishader_v, uishader_v_size);
45 if (vertexShader == NULL) {
46 return false;
47 }
48
49 // Load geometry shader binary
50 geometryShader = DVLB_ParseFile((u32*) uishader_g, uishader_g_size);
51 if (geometryShader == NULL) {
52 return false;
53 }
54
55 // Create shader
56 shaderProgramInit(&gpuShader);
57 Result res = shaderProgramSetVsh(&gpuShader, &vertexShader->DVLE[0]);
58 if (res < 0) {
59 return false;
60 }
61 res = shaderProgramSetGsh(&gpuShader, &geometryShader->DVLE[0], 3);
62 if (res < 0) {
63 return false;
64 }
65 C3D_BindProgram(&gpuShader);
66
67 // Allocate buffers
68 ctrVertexBuffer = linearAlloc(VERTEX_BUFFER_SIZE);
69 if (ctrVertexBuffer == NULL) {
70 return false;
71 }
72
73 // Set up TexEnv and other parameters
74 C3D_TexEnv* env = C3D_GetTexEnv(0);
75 C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
76 C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
77 C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
78
79 C3D_CullFace(GPU_CULL_NONE);
80 C3D_DepthTest(false, GPU_ALWAYS, GPU_WRITE_ALL);
81 C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
82 C3D_AlphaTest(false, GPU_ALWAYS, 0);
83 C3D_BlendingColor(0);
84
85 C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
86 AttrInfo_Init(attrInfo);
87 AttrInfo_AddLoader(attrInfo, 0, GPU_SHORT, 4); // in_pos
88 AttrInfo_AddLoader(attrInfo, 1, GPU_SHORT, 4); // in_tc0
89 AttrInfo_AddLoader(attrInfo, 2, GPU_UNSIGNED_BYTE, 4); // in_col
90
91 C3D_BufInfo* bufInfo = C3D_GetBufInfo();
92 BufInfo_Init(bufInfo);
93 BufInfo_Add(bufInfo, ctrVertexBuffer, sizeof(struct ctrUIVertex), 3, 0x210);
94
95 return true;
96}
97
98void ctrDeinitGpu() {
99 if (ctrVertexBuffer) {
100 linearFree(ctrVertexBuffer);
101 ctrVertexBuffer = NULL;
102 }
103
104 shaderProgramFree(&gpuShader);
105
106 if (vertexShader) {
107 DVLB_Free(vertexShader);
108 vertexShader = NULL;
109 }
110
111 if (geometryShader) {
112 DVLB_Free(geometryShader);
113 geometryShader = NULL;
114 }
115}
116
117void ctrSetViewportSize(s16 w, s16 h) {
118 C3D_SetViewport(0, 0, h, w);
119 C3D_Mtx projectionMtx;
120 Mtx_OrthoTilt(&projectionMtx, 0.0, w, h, 0.0, 0.0, 1.0);
121 C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx);
122}
123
124void ctrActivateTexture(C3D_Tex* texture) {
125 if (texture == activeTexture) {
126 return;
127 }
128 if (activeTexture) {
129 ctrFlushBatch();
130 }
131
132 C3D_TexBind(0, texture);
133 activeTexture = texture;
134
135 C3D_Mtx textureMtx = {
136 .m = {
137 // Rows are in the order w z y x, because ctrulib
138 0.0f, 0.0f, 0.0f, 1.0f / activeTexture->width,
139 0.0f, 0.0f, 1.0f / activeTexture->height, 0.0f
140 }
141 };
142 C3D_FVUnifMtx2x4(GPU_GEOMETRY_SHADER, GSH_FVEC_textureMtx, &textureMtx);
143}
144
145void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh) {
146 if (ctrNumQuads == MAX_NUM_QUADS) {
147 ctrFlushBatch();
148 }
149
150 struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrNumQuads];
151 vtx->x = x;
152 vtx->y = y;
153 vtx->w = w;
154 vtx->h = h;
155 vtx->u = u;
156 vtx->v = v;
157 vtx->uw = uw;
158 vtx->vh = vh;
159 vtx->abgr = color;
160
161 ++ctrNumQuads;
162}
163
164void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h) {
165 ctrAddRectScaled(color, x, y, w, h, u, v, w, h);
166}
167
168void ctrFlushBatch(void) {
169 if (ctrNumQuads == 0) {
170 return;
171 }
172
173 GSPGPU_FlushDataCache(ctrVertexBuffer, VERTEX_BUFFER_SIZE);
174 C3D_DrawArrays(GPU_GEOMETRY_PRIM, 0, ctrNumQuads);
175 C3D_Flush();
176
177 ctrNumQuads = 0;
178}