1 /* originally from from https://github.com/smealum/ctrulib */
2 
3 /*
4   gpu-old.c _ Legacy GPU commands.
5 */
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include <3ds/types.h>
10 #include <3ds/gpu/gpu.h>
11 #include <3ds/gpu/gx.h>
12 #include <3ds/gpu/shbin.h>
13 
14 #include "gpu_old.h"
15 
GPU_Init(Handle * gsphandle)16 void GPU_Init(Handle *gsphandle)
17 {
18 	gpuCmdBuf       = NULL;
19 	gpuCmdBufSize   = 0;
20 	gpuCmdBufOffset = 0;
21 }
22 
GPU_Reset(u32 * gxbuf,u32 * gpuBuf,u32 gpuBufSize)23 void GPU_Reset(u32* gxbuf, u32* gpuBuf, u32 gpuBufSize)
24 {
25 	GPUCMD_SetBuffer(gpuBuf, gpuBufSize, 0);
26 }
27 
GPU_SetFloatUniform(GPU_SHADER_TYPE type,u32 startreg,u32 * data,u32 numreg)28 void GPU_SetFloatUniform(GPU_SHADER_TYPE type,
29       u32 startreg, u32* data, u32 numreg)
30 {
31    int regOffset = 0x0;;
32    if (!data)
33       return;
34 
35    if (type == GPU_GEOMETRY_SHADER)
36       regOffset = (-0x30);
37 
38    GPUCMD_AddWrite(GPUREG_VSH_FLOATUNIFORM_CONFIG+regOffset,
39          0x80000000 | startreg);
40    GPUCMD_AddWrites(GPUREG_VSH_FLOATUNIFORM_DATA+regOffset, data, numreg*4);
41 }
42 
43 /* takes PAs as arguments */
GPU_SetViewport(u32 * depthBuffer,u32 * colorBuffer,u32 x,u32 y,u32 w,u32 h)44 void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer,
45       u32 x, u32 y, u32 w, u32 h)
46 {
47    u32 f116e;
48 	u32 param[0x4];
49 	float fw   = (float)w;
50 	float fh   = (float)h;
51 
52 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
53 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
54 
55 	f116e      = 0x01000000 | (((h-1) & 0xFFF) << 12) | (w & 0xFFF);
56 
57 	param[0x0] = ((u32)depthBuffer) >> 3;
58 	param[0x1] = ((u32)colorBuffer) >> 3;
59 	param[0x2] = f116e;
60 	GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, param, 0x00000003);
61 
62 	GPUCMD_AddWrite(GPUREG_RENDERBUF_DIM, f116e);
63    /* depth buffer format */
64 	GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, 0x00000003);
65    /* color buffer format */
66 	GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, 0x00000002);
67 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_BLOCK32, 0x00000000); /* ? */
68 
69 	param[0x0] = f32tof24(fw/2);
70 	param[0x1] = f32tof31(2.0f / fw) << 1;
71 	param[0x2] = f32tof24(fh/2);
72 	param[0x3] = f32tof31(2.0f / fh) << 1;
73 	GPUCMD_AddIncrementalWrites(GPUREG_VIEWPORT_WIDTH, param, 0x00000004);
74 
75 	GPUCMD_AddWrite(GPUREG_VIEWPORT_XY, (y << 16)|(x & 0xFFFF));
76 
77 	param[0x0] = 0x00000000;
78 	param[0x1] = 0x00000000;
79 	param[0x2] = ((h-1) << 16)|((w-1) & 0xFFFF);
80 	GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, param, 0x00000003);
81 
82 	/* enable depth buffer */
83 	param[0x0] = 0x0000000F;
84 	param[0x1] = 0x0000000F;
85 	param[0x2] = 0x00000002;
86 	param[0x3] = 0x00000002;
87 	GPUCMD_AddIncrementalWrites(GPUREG_COLORBUFFER_READ, param, 0x00000004);
88 }
89 
GPU_SetScissorTest(GPU_SCISSORMODE mode,u32 left,u32 bottom,u32 right,u32 top)90 void GPU_SetScissorTest(GPU_SCISSORMODE mode, u32 left, u32 bottom, u32 right, u32 top)
91 {
92 	u32 param[3];
93 
94 	param[0x0] = mode;
95 	param[0x1] = (bottom << 16)  | (left & 0xFFFF);
96 	param[0x2] = ((top-1) << 16) | ((right-1) & 0xFFFF);
97 	GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, param, 0x00000003);
98 }
99 
GPU_DepthMap(float zScale,float zOffset)100 void GPU_DepthMap(float zScale, float zOffset)
101 {
102 	GPUCMD_AddWrite(GPUREG_DEPTHMAP_ENABLE, 0x00000001);
103 	GPUCMD_AddWrite(GPUREG_DEPTHMAP_SCALE, f32tof24(zScale));
104 	GPUCMD_AddWrite(GPUREG_DEPTHMAP_OFFSET, f32tof24(zOffset));
105 }
106 
GPU_SetAlphaTest(bool enable,GPU_TESTFUNC function,u8 ref)107 void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref)
108 {
109 	GPUCMD_AddWrite(GPUREG_FRAGOP_ALPHA_TEST,
110          (enable&1)|((function&7) << 4)|(ref << 8));
111 }
112 
GPU_SetStencilTest(bool enable,GPU_TESTFUNC function,u8 ref,u8 input_mask,u8 write_mask)113 void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 input_mask, u8 write_mask)
114 {
115 	GPUCMD_AddWrite(GPUREG_STENCIL_TEST,
116          (enable&1)|((function&7) << 4)|(write_mask << 8)|(ref << 16)|(input_mask << 24));
117 }
118 
GPU_SetStencilOp(GPU_STENCILOP sfail,GPU_STENCILOP dfail,GPU_STENCILOP pass)119 void GPU_SetStencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass)
120 {
121 	GPUCMD_AddWrite(GPUREG_STENCIL_OP, sfail | (dfail << 4) | (pass << 8));
122 }
123 
GPU_SetDepthTestAndWriteMask(bool enable,GPU_TESTFUNC function,GPU_WRITEMASK writemask)124 void GPU_SetDepthTestAndWriteMask(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask)
125 {
126 	GPUCMD_AddWrite(GPUREG_DEPTH_COLOR_MASK, (enable&1)|((function&7) << 4)|(writemask << 8));
127 }
128 
GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation,GPU_BLENDEQUATION alphaEquation,GPU_BLENDFACTOR colorSrc,GPU_BLENDFACTOR colorDst,GPU_BLENDFACTOR alphaSrc,GPU_BLENDFACTOR alphaDst)129 void GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation, GPU_BLENDEQUATION alphaEquation,
130 	GPU_BLENDFACTOR colorSrc, GPU_BLENDFACTOR colorDst,
131 	GPU_BLENDFACTOR alphaSrc, GPU_BLENDFACTOR alphaDst)
132 {
133 	GPUCMD_AddWrite(GPUREG_BLEND_FUNC, colorEquation | (alphaEquation << 8) | (colorSrc << 16) | (colorDst << 20) | (alphaSrc << 24) | (alphaDst << 28));
134 	GPUCMD_AddMaskedWrite(GPUREG_COLOR_OPERATION, 0x2, 0x00000100);
135 }
136 
GPU_SetColorLogicOp(GPU_LOGICOP op)137 void GPU_SetColorLogicOp(GPU_LOGICOP op)
138 {
139 	GPUCMD_AddWrite(GPUREG_LOGIC_OP, op);
140 	GPUCMD_AddMaskedWrite(GPUREG_COLOR_OPERATION, 0x2, 0x00000000);
141 }
142 
GPU_SetBlendingColor(u8 r,u8 g,u8 b,u8 a)143 void GPU_SetBlendingColor(u8 r, u8 g, u8 b, u8 a)
144 {
145 	GPUCMD_AddWrite(GPUREG_BLEND_COLOR, r | (g << 8) | (b << 16) | (a << 24));
146 }
147 
GPU_SetTextureEnable(GPU_TEXUNIT units)148 void GPU_SetTextureEnable(GPU_TEXUNIT units)
149 {
150 	GPUCMD_AddMaskedWrite(GPUREG_SH_OUTATTR_CLOCK, 0x2, units << 8); /* enables texcoord outputs */
151 	GPUCMD_AddWrite(GPUREG_TEXUNIT_CONFIG, 0x00011000|units); /* enables texture units */
152 }
153 
GPU_SetTexture(GPU_TEXUNIT unit,u32 * data,u16 width,u16 height,u32 param,GPU_TEXCOLOR colorType)154 void GPU_SetTexture(GPU_TEXUNIT unit, u32* data, u16 width, u16 height, u32 param, GPU_TEXCOLOR colorType)
155 {
156 	switch (unit)
157    {
158       case GPU_TEXUNIT0:
159          GPUCMD_AddWrite(GPUREG_TEXUNIT0_TYPE, colorType);
160          GPUCMD_AddWrite(GPUREG_TEXUNIT0_ADDR1, ((u32)data) >> 3);
161          GPUCMD_AddWrite(GPUREG_TEXUNIT0_DIM, (width << 16)|height);
162          GPUCMD_AddWrite(GPUREG_TEXUNIT0_PARAM, param);
163          break;
164 
165       case GPU_TEXUNIT1:
166          GPUCMD_AddWrite(GPUREG_TEXUNIT1_TYPE, colorType);
167          GPUCMD_AddWrite(GPUREG_TEXUNIT1_ADDR, ((u32)data) >> 3);
168          GPUCMD_AddWrite(GPUREG_TEXUNIT1_DIM, (width << 16)|height);
169          GPUCMD_AddWrite(GPUREG_TEXUNIT1_PARAM, param);
170          break;
171 
172       case GPU_TEXUNIT2:
173          GPUCMD_AddWrite(GPUREG_TEXUNIT2_TYPE, colorType);
174          GPUCMD_AddWrite(GPUREG_TEXUNIT2_ADDR, ((u32)data) >> 3);
175          GPUCMD_AddWrite(GPUREG_TEXUNIT2_DIM, (width << 16)|height);
176          GPUCMD_AddWrite(GPUREG_TEXUNIT2_PARAM, param);
177          break;
178    }
179 }
180 
GPU_SetTextureBorderColor(GPU_TEXUNIT unit,u32 borderColor)181 void GPU_SetTextureBorderColor(GPU_TEXUNIT unit,u32 borderColor)
182 {
183 	switch (unit)
184    {
185       case GPU_TEXUNIT0:
186          GPUCMD_AddWrite(GPUREG_TEXUNIT0_BORDER_COLOR, borderColor);
187          break;
188 
189       case GPU_TEXUNIT1:
190          GPUCMD_AddWrite(GPUREG_TEXUNIT1_BORDER_COLOR, borderColor);
191          break;
192 
193       case GPU_TEXUNIT2:
194          GPUCMD_AddWrite(GPUREG_TEXUNIT2_BORDER_COLOR, borderColor);
195          break;
196    }
197 }
198 
199 const u8 GPU_FORMATSIZE[4]={1,1,2,4};
200 
GPU_SetAttributeBuffers(u8 totalAttributes,u32 * baseAddress,u64 attributeFormats,u16 attributeMask,u64 attributePermutation,u8 numBuffers,u32 bufferOffsets[],u64 bufferPermutations[],u8 bufferNumAttributes[])201 void GPU_SetAttributeBuffers(
202       u8 totalAttributes,
203       u32* baseAddress,
204       u64 attributeFormats,
205       u16 attributeMask,
206       u64 attributePermutation,
207       u8 numBuffers,
208       u32 bufferOffsets[],
209       u64 bufferPermutations[],
210       u8 bufferNumAttributes[])
211 {
212 	int i, j;
213 	u32 param[0x28];
214 	u8 sizeTable[0xC];
215 
216 	memset(param, 0x00, 0x28*4);
217 
218 	param[0x0] = ((u32)baseAddress) >> 3;
219 	param[0x1] = attributeFormats & 0xFFFFFFFF;
220 	param[0x2] = ((totalAttributes-1) << 28) | ((attributeMask & 0xFFF) << 16) | ((attributeFormats >> 32) & 0xFFFF);
221 
222 	for (i = 0; i < totalAttributes; i++)
223 	{
224 		u8 v               = attributeFormats & 0xF;
225 		sizeTable[i]       = GPU_FORMATSIZE[v & 3]*((v>>2)+1);
226 		attributeFormats >>= 4;
227 	}
228 
229 	for (i = 0; i < numBuffers; i++)
230 	{
231 		u16 stride       = 0;
232 		param[3*(i+1)+0] = bufferOffsets[i];
233 		param[3*(i+1)+1] = bufferPermutations[i] & 0xFFFFFFFF;
234 		for (j = 0; j < bufferNumAttributes[i]; j++)
235          stride += sizeTable[(bufferPermutations[i]>>(4*j)) & 0xF];
236 
237 		param[3*(i+1)+2] = (bufferNumAttributes[i] << 28) | ((stride & 0xFFF)<< 16) | ((bufferPermutations[i] >> 32) & 0xFFFF);
238 	}
239 
240 	GPUCMD_AddIncrementalWrites(GPUREG_ATTRIBBUFFERS_LOC, param, 0x00000027);
241 
242 	GPUCMD_AddMaskedWrite(GPUREG_VSH_INPUTBUFFER_CONFIG, 0xB, 0xA0000000|(totalAttributes-1));
243 	GPUCMD_AddWrite(GPUREG_VSH_NUM_ATTR, (totalAttributes-1));
244 
245 	GPUCMD_AddIncrementalWrites(GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW, ((u32[]){attributePermutation & 0xFFFFFFFF, (attributePermutation >> 32) & 0xFFFF}), 2);
246 }
247 
GPU_SetAttributeBuffersAddress(u32 * baseAddress)248 void GPU_SetAttributeBuffersAddress(u32* baseAddress)
249 {
250 	GPUCMD_AddWrite(GPUREG_ATTRIBBUFFERS_LOC, ((u32)baseAddress) >> 3);
251 }
252 
GPU_SetFaceCulling(GPU_CULLMODE mode)253 void GPU_SetFaceCulling(GPU_CULLMODE mode)
254 {
255 	GPUCMD_AddWrite(GPUREG_FACECULLING_CONFIG, mode & 0x3);
256 }
257 
GPU_SetCombinerBufferWrite(u8 rgb_config,u8 alpha_config)258 void GPU_SetCombinerBufferWrite(u8 rgb_config, u8 alpha_config)
259 {
260     GPUCMD_AddMaskedWrite(GPUREG_TEXENV_UPDATE_BUFFER, 0x2, (rgb_config << 8) | (alpha_config << 12));
261 }
262 
263 const u8 GPU_TEVID[]={0xC0,0xC8,0xD0,0xD8,0xF0,0xF8};
264 
GPU_SetTexEnv(u8 id,u16 rgbSources,u16 alphaSources,u16 rgbOperands,u16 alphaOperands,GPU_COMBINEFUNC rgbCombine,GPU_COMBINEFUNC alphaCombine,u32 constantColor)265 void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor)
266 {
267 	u32 param[0x5];
268 	if(id > 6)
269       return;
270 
271 	param[0x0] = (alphaSources  << 16) | (rgbSources);
272 	param[0x1] = (alphaOperands << 12) | (rgbOperands);
273 	param[0x2] = (alphaCombine  << 16) | (rgbCombine);
274 	param[0x3] = constantColor;
275 	param[0x4] = 0x00000000; /* ? */
276 
277 	GPUCMD_AddIncrementalWrites(GPUREG_0000|GPU_TEVID[id], param, 0x00000005);
278 }
279 
GPU_DrawArray(GPU_Primitive_t primitive,u32 first,u32 count)280 void GPU_DrawArray(GPU_Primitive_t primitive, u32 first, u32 count)
281 {
282 	/* set primitive type */
283 	GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x2, primitive);
284 	GPUCMD_AddMaskedWrite(GPUREG_RESTART_PRIMITIVE, 0x2, 0x00000001);
285 	/* index buffer address register should be cleared
286     * (except bit 31) before drawing */
287 	GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000);
288 	/* pass number of vertices */
289 	GPUCMD_AddWrite(GPUREG_NUMVERTICES, count);
290 	/* set first vertex */
291 	GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, first);
292 
293 	/* all the following except 0x000F022E might be useless */
294 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 0x1, 0x00000001);
295 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000000);
296 	GPUCMD_AddWrite(GPUREG_DRAWARRAYS, 0x00000001);
297 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000001);
298 	GPUCMD_AddWrite(GPUREG_VTX_FUNC, 0x00000001);
299 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
300 }
301 
GPU_DrawElements(GPU_Primitive_t primitive,u32 * indexArray,u32 n)302 void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n)
303 {
304 	/* set primitive type */
305 	GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x2, primitive);
306 	GPUCMD_AddMaskedWrite(GPUREG_RESTART_PRIMITIVE, 0x2, 0x00000001);
307 	/* index buffer (TODO : support multiple types) */
308 	GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000|((u32)indexArray));
309 	/* pass number of vertices */
310 	GPUCMD_AddWrite(GPUREG_NUMVERTICES, n);
311 
312 	GPUCMD_AddWrite(GPUREG_VERTEX_OFFSET, 0x00000000);
313 
314 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x2, 0x00000100);
315 	GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG2, 0x2, 0x00000100);
316 
317 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000000);
318 	GPUCMD_AddWrite(GPUREG_DRAWELEMENTS, 0x00000001);
319 	GPUCMD_AddMaskedWrite(GPUREG_START_DRAW_FUNC0, 0x1, 0x00000001);
320 	GPUCMD_AddWrite(GPUREG_VTX_FUNC, 0x00000001);
321 
322 	/* CHECKME: does this one also require
323     * GPUREG_FRAMEBUFFER_FLUSH at the end? */
324 }
325 
GPU_FinishDrawing(void)326 void GPU_FinishDrawing(void)
327 {
328 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
329 	GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
330 	GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 0x00000001);
331 }
332 
GPU_Finalize(void)333 void GPU_Finalize(void)
334 {
335    GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x8, 0x00000000);
336    GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
337    GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
338 #if 0
339    GPUCMD_Split(NULL, NULL);
340 #else
341    GPUCMD_AddWrite(GPUREG_FINALIZE, 0x12345678);
342    /* not the cleanest way of guaranteeing 0x10-byte size
343     * but whatever good enough for now */
344    GPUCMD_AddWrite(GPUREG_FINALIZE,0x12345678);
345 #endif
346 }
347