all repos — mgba @ 7c058ea13ff03f78d0610944747ebfaabbd24bb4

mGBA Game Boy Advance Emulator

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.h"
 18#include "uishader.shbin.h"
 19
 20struct ctrUIVertex {
 21	short x, y;
 22	short w, h;
 23	short u, v;
 24	short uw, vh;
 25	u32 abgr;
 26	float rotate[2];
 27};
 28
 29#define MAX_NUM_QUADS 4096
 30#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex)
 31
 32static struct ctrUIVertex* ctrVertexBuffer = NULL;
 33static int ctrNumVerts = 0;
 34static int ctrVertStart = 0;
 35
 36static const C3D_Tex* activeTexture = NULL;
 37
 38static shaderProgram_s uiProgram;
 39static DVLB_s* uiShader = NULL;
 40static int GSH_FVEC_projectionMtx;
 41static int GSH_FVEC_textureMtx;
 42
 43bool ctrInitGpu(void) {
 44	// Load vertex shader binary
 45	uiShader = DVLB_ParseFile((u32*) uishader, uishader_size);
 46	if (uiShader == NULL) {
 47		return false;
 48	}
 49
 50	// Create shader
 51	shaderProgramInit(&uiProgram);
 52	Result res = shaderProgramSetVsh(&uiProgram, &uiShader->DVLE[0]);
 53	if (res < 0) {
 54		return false;
 55	}
 56	res = shaderProgramSetGsh(&uiProgram, &uiShader->DVLE[1], 4);
 57	if (res < 0) {
 58		return false;
 59	}
 60	C3D_BindProgram(&uiProgram);
 61	GSH_FVEC_projectionMtx = shaderInstanceGetUniformLocation(uiProgram.geometryShader, "projectionMtx");
 62	GSH_FVEC_textureMtx = shaderInstanceGetUniformLocation(uiProgram.geometryShader, "textureMtx");
 63
 64	// Allocate buffers
 65	ctrVertexBuffer = linearAlloc(VERTEX_BUFFER_SIZE);
 66	if (ctrVertexBuffer == NULL) {
 67		return false;
 68	}
 69
 70	C3D_CullFace(GPU_CULL_NONE);
 71	C3D_DepthTest(false, GPU_ALWAYS, GPU_WRITE_ALL);
 72	C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
 73	C3D_AlphaTest(false, GPU_ALWAYS, 0);
 74	C3D_BlendingColor(0);
 75
 76	C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
 77	AttrInfo_Init(attrInfo);
 78	AttrInfo_AddLoader(attrInfo, 0, GPU_SHORT, 4); // in_pos
 79	AttrInfo_AddLoader(attrInfo, 1, GPU_SHORT, 4); // in_tc0
 80	AttrInfo_AddLoader(attrInfo, 2, GPU_UNSIGNED_BYTE, 4); // in_col
 81	AttrInfo_AddLoader(attrInfo, 3, GPU_FLOAT, 2); // in_rot
 82
 83	return true;
 84}
 85
 86void ctrDeinitGpu(void) {
 87	if (ctrVertexBuffer) {
 88		linearFree(ctrVertexBuffer);
 89		ctrVertexBuffer = NULL;
 90	}
 91
 92	shaderProgramFree(&uiProgram);
 93
 94	if (uiShader) {
 95		DVLB_Free(uiShader);
 96		uiShader = NULL;
 97	}
 98}
 99
100void ctrSetViewportSize(s16 w, s16 h, bool tilt) {
101	C3D_SetViewport(0, 0, h, w);
102	C3D_Mtx projectionMtx;
103	if (tilt) {
104		Mtx_OrthoTilt(&projectionMtx, 0.0, w, h, 0.0, 0.0, 1.0, true);
105	} else {
106		Mtx_Ortho(&projectionMtx, 0.0, w, 0.0, h, 0.0, 1.0, true);
107	}
108	C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx);
109}
110
111void ctrFlushBatch(void) {
112	int thisBatch = ctrNumVerts - ctrVertStart;
113	if (!thisBatch) {
114		return;
115	}
116	if (thisBatch < 0) {
117		svcBreak(USERBREAK_PANIC);
118	}
119	C3D_DrawArrays(GPU_GEOMETRY_PRIM, ctrVertStart, thisBatch);
120	ctrVertStart = ctrNumVerts;
121}
122
123void ctrActivateTexture(const C3D_Tex* texture) {
124	if (texture == activeTexture) {
125		return;
126	}
127
128	if (activeTexture) {
129		ctrFlushBatch();
130	}
131
132	activeTexture = texture;
133	C3D_TexBind(0, activeTexture);
134
135	C3D_TexEnv* env = C3D_GetTexEnv(0);
136	C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
137	if (texture->fmt < GPU_LA8) {
138		C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
139		C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
140	} else {
141		C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR, 0, 0);
142		C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0);
143		C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE);
144		C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE);
145	}
146	env = C3D_GetTexEnv(1);
147	C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
148	C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, 0, 0);
149	C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
150	env = C3D_GetTexEnv(2);
151	C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
152	C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, 0, 0);
153	C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
154
155	C3D_Mtx textureMtx = {
156		.m = {
157			// Rows are in the order w z y x, because ctrulib
158			0.0f, 0.0f, 0.0f, 1.0f / activeTexture->width,
159			0.0f, 0.0f, 1.0f / activeTexture->height, 0.0f 
160		}
161	};
162	C3D_FVUnifMtx2x4(GPU_GEOMETRY_SHADER, GSH_FVEC_textureMtx, &textureMtx);
163}
164
165void ctrTextureMultiply(void) {
166	C3D_TexEnv* env = C3D_GetTexEnv(1);
167	C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
168	C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, GPU_TEXTURE0, 0);
169	C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE);
170}
171
172void ctrTextureBias(u32 color) {
173	C3D_TexEnv* env = C3D_GetTexEnv(2);
174	C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
175	C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, GPU_CONSTANT, 0);
176	C3D_TexEnvFunc(env, C3D_Both, GPU_ADD);
177	C3D_TexEnvColor(env, color);
178}
179
180void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh, float rotate) {
181	if (x >= 400 && w >= 0) {
182		return;
183	}
184	if (y >= 240 && h >= 0) {
185		return;
186	}
187
188	if (ctrNumVerts == MAX_NUM_QUADS) {
189		abort();
190	}
191
192	struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrNumVerts];
193	vtx->x = x;
194	vtx->y = y;
195	vtx->w = w;
196	vtx->h = h;
197	vtx->u = u;
198	vtx->v = v;
199	vtx->uw = uw;
200	vtx->vh = vh;
201	vtx->abgr = color;
202	vtx->rotate[0] = cosf(rotate);
203	vtx->rotate[1] = sinf(rotate);
204
205	++ctrNumVerts;
206}
207
208void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h) {
209	ctrAddRectEx(color, x, y, w, h, u, v, w, h, 0);
210}
211
212void ctrStartFrame(void) {
213	ctrNumVerts = 0;
214	ctrVertStart = 0;
215	activeTexture = NULL;
216
217	C3D_BufInfo* bufInfo = C3D_GetBufInfo();
218	BufInfo_Init(bufInfo);
219	BufInfo_Add(bufInfo, ctrVertexBuffer, sizeof(struct ctrUIVertex), 4, 0x3210);
220}
221
222void ctrEndFrame(void) {
223	ctrFlushBatch();
224	GSPGPU_FlushDataCache(ctrVertexBuffer, sizeof(struct ctrUIVertex) * ctrNumVerts);
225}