all repos — mgba @ 7930c5a350fc21b233cc9cfdab058de1da79619a

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_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}