summary refs log tree commit diff
path: root/src/Graphics_WiiU.c
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Graphics_WiiU.c
initial commit
Diffstat (limited to 'src/Graphics_WiiU.c')
-rw-r--r--src/Graphics_WiiU.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/src/Graphics_WiiU.c b/src/Graphics_WiiU.c
new file mode 100644
index 0000000..da1cce1
--- /dev/null
+++ b/src/Graphics_WiiU.c
@@ -0,0 +1,481 @@
+#include "Core.h"
+#ifdef CC_BUILD_WIIU
+#include "_GraphicsBase.h"
+#include "Errors.h"
+#include "Window.h"
+#include <gx2/clear.h>
+#include <gx2/context.h>
+#include <gx2/display.h>
+#include <gx2/draw.h>
+#include <gx2/event.h>
+#include <gx2/mem.h>
+#include <gx2/registers.h>
+#include <gx2/shaders.h>
+#include <gx2/state.h>
+#include <gx2/surface.h>
+#include <gx2/swap.h>
+#include <gx2/temp.h>
+#include <gx2/utils.h>
+#include <gx2r/draw.h>
+#include <gx2r/mem.h>
+#include <gx2r/buffer.h>
+#include <whb/gfx.h>
+#include <coreinit/memdefaultheap.h>
+#include "../build-wiiu/coloured_gsh.h"
+#include "../build-wiiu/textured_gsh.h"
+
+static WHBGfxShaderGroup colorShader;
+static WHBGfxShaderGroup textureShader;
+static GX2Sampler sampler;
+static GfxResourceID white_square;
+static WHBGfxShaderGroup* group;
+
+static void InitGfx(void) {
+   	GX2InitSampler(&sampler, GX2_TEX_CLAMP_MODE_WRAP, GX2_TEX_XY_FILTER_MODE_POINT);
+	
+	WHBGfxLoadGFDShaderGroup(&colorShader, 0, coloured_gsh);
+	WHBGfxInitShaderAttribute(&colorShader, "in_pos", 0,  0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
+	WHBGfxInitShaderAttribute(&colorShader, "in_col", 0, 12, GX2_ATTRIB_FORMAT_UNORM_8_8_8_8);
+	WHBGfxInitFetchShader(&colorShader);
+	
+	WHBGfxLoadGFDShaderGroup(&textureShader, 0, textured_gsh);
+	WHBGfxInitShaderAttribute(&textureShader, "in_pos", 0,  0, GX2_ATTRIB_FORMAT_FLOAT_32_32_32);
+	WHBGfxInitShaderAttribute(&textureShader, "in_col", 0, 12, GX2_ATTRIB_FORMAT_UNORM_8_8_8_8);
+	WHBGfxInitShaderAttribute(&textureShader, "in_uv",  0, 16, GX2_ATTRIB_FORMAT_FLOAT_32_32);
+	WHBGfxInitFetchShader(&textureShader);
+}
+
+void Gfx_Create(void) {
+	if (!Gfx.Created) InitGfx();
+	
+	Gfx.Created      = true;
+	Gfx.MaxTexWidth  = 1024;
+	Gfx.MaxTexHeight = 1024;
+}
+
+cc_bool Gfx_TryRestoreContext(void) {
+	return true;
+}
+
+void Gfx_Free(void) {
+	Gfx_FreeState();
+}
+
+static void Gfx_FreeState(void) { 
+	FreeDefaultResources();
+	Gfx_DeleteTexture(&white_square);
+}
+
+static void Gfx_RestoreState(void) {
+	Gfx_SetFaceCulling(false);
+	InitDefaultResources();
+	gfx_format = -1;
+	
+	// 1x1 dummy white texture
+	struct Bitmap bmp;
+	BitmapCol pixels[1] = { BITMAPCOLOR_WHITE };
+	Bitmap_Init(bmp, 1, 1, pixels);
+	white_square = Gfx_CreateTexture(&bmp, 0, false);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Textures--------------------------------------------------------*
+*#########################################################################################################################*/
+static GX2Texture* pendingTex;
+
+static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) {
+	GX2Texture* tex = Mem_TryAllocCleared(1, sizeof(GX2Texture));
+	if (!tex) return NULL;
+
+	// TODO handle out of memory better
+	int width = bmp->width, height = bmp->height;
+	tex->surface.width    = width;
+	tex->surface.height   = height;
+	tex->surface.depth    = 1;
+	tex->surface.dim      = GX2_SURFACE_DIM_TEXTURE_2D;
+	tex->surface.format   = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8;
+	tex->surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED;
+	tex->viewNumSlices    = 1;
+	tex->compMap          = GX2_COMP_MAP(GX2_SQ_SEL_R, GX2_SQ_SEL_G, GX2_SQ_SEL_B, GX2_SQ_SEL_A);
+	GX2CalcSurfaceSizeAndAlignment(&tex->surface);
+	GX2InitTextureRegs(tex);
+
+	tex->surface.image = MEMAllocFromDefaultHeapEx(tex->surface.imageSize, tex->surface.alignment);
+	if (!tex->surface.image) { Mem_Free(tex); return NULL; }
+  
+	CopyTextureData(tex->surface.image, tex->surface.pitch << 2, bmp, rowWidth << 2);
+	GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, tex->surface.image, tex->surface.imageSize);
+	return tex;
+}
+
+void Gfx_UpdateTexture(GfxResourceID texId, int x, int y, struct Bitmap* part, int rowWidth, cc_bool mipmaps) {
+	GX2Texture* tex = (GX2Texture*)texId;	
+	uint32_t* dst   = (uint32_t*)tex->surface.image + (y * tex->surface.pitch) + x;
+	
+	CopyTextureData(dst, tex->surface.pitch << 2, part, rowWidth << 2);
+	GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, tex->surface.image, tex->surface.imageSize);
+}
+
+void Gfx_BindTexture(GfxResourceID texId) {
+	if (!texId) texId = white_square;
+	pendingTex = (GX2Texture*)texId;
+	// Texture is bound to active shader, so might need to defer it in
+	//  case a call to Gfx_BindTexture was called even though vertex format wasn't textured
+	// TODO: Track as dirty uniform flag instead?
+}
+
+static void BindPendingTexture(void) {
+	if (!pendingTex || group != &textureShader) return;
+	
+	GX2SetPixelTexture(pendingTex, group->pixelShader->samplerVars[0].location);
+	GX2SetPixelSampler(&sampler,   group->pixelShader->samplerVars[0].location);
+ 	pendingTex = NULL;
+}
+
+void Gfx_DeleteTexture(GfxResourceID* texId) {
+	if (*texId == pendingTex) pendingTex = NULL;
+	// TODO free memory ???
+}
+
+void Gfx_EnableMipmaps(void) { }  // TODO
+
+void Gfx_DisableMipmaps(void) { } // TODO
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------State management----------------------------------------------------*
+*#########################################################################################################################*/
+static float clearR, clearG, clearB;
+static cc_bool depthWrite = true, depthTest = true;
+
+static void UpdateDepthState(void) {
+	GX2SetDepthOnlyControl(depthTest, depthWrite, GX2_COMPARE_FUNC_LEQUAL);
+}
+
+void Gfx_SetFaceCulling(cc_bool enabled) {
+	GX2SetCullOnlyControl(GX2_FRONT_FACE_CCW, false, enabled);
+}
+
+void Gfx_SetFog(cc_bool enabled) {
+	// TODO
+}
+
+void Gfx_SetFogCol(PackedCol color) {
+	// TODO
+}
+
+void Gfx_SetFogDensity(float value) {
+	// TODO
+}
+
+void Gfx_SetFogEnd(float value) {
+	// TODO
+}
+
+void Gfx_SetFogMode(FogFunc func) {
+	// TODO
+}
+
+static void SetAlphaTest(cc_bool enabled) {
+	GX2SetAlphaTest(enabled, GX2_COMPARE_FUNC_GEQUAL, 0.5f);
+}
+
+static void SetAlphaBlend(cc_bool enabled) {
+	GX2SetBlendControl(GX2_RENDER_TARGET_0,
+		GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD,
+		true,
+		GX2_BLEND_MODE_SRC_ALPHA, GX2_BLEND_MODE_INV_SRC_ALPHA, GX2_BLEND_COMBINE_MODE_ADD);
+	GX2SetColorControl(GX2_LOGIC_OP_COPY, enabled, FALSE, TRUE);
+}
+
+void Gfx_SetAlphaArgBlend(cc_bool enabled) {
+}
+
+void Gfx_ClearColor(PackedCol color) {
+	clearR = PackedCol_R(color) / 255.0f;
+	clearG = PackedCol_G(color) / 255.0f;
+	clearB = PackedCol_B(color) / 255.0f;
+}
+
+void Gfx_SetDepthTest(cc_bool enabled) {
+	depthTest = enabled;
+	UpdateDepthState();
+}
+
+void Gfx_SetDepthWrite(cc_bool enabled) {
+	depthWrite = enabled;
+	UpdateDepthState();
+}
+
+static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) {
+	GX2ChannelMask mask = 0;
+	if (r) mask |= GX2_CHANNEL_MASK_R;
+	if (g) mask |= GX2_CHANNEL_MASK_G;
+	if (b) mask |= GX2_CHANNEL_MASK_B;
+	if (a) mask |= GX2_CHANNEL_MASK_A;
+	
+	// TODO: use GX2SetColorControl to disable all writing ???
+	GX2SetTargetChannelMasks(mask, 0,0,0, 0,0,0,0);
+}
+
+void Gfx_DepthOnlyRendering(cc_bool depthOnly) {
+	cc_bool enabled = !depthOnly;
+	SetColorWrite(enabled & gfx_colorMask[0], enabled & gfx_colorMask[1], 
+				  enabled & gfx_colorMask[2], enabled & gfx_colorMask[3]);
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Index buffers-----------------------------------------------------*
+*#########################################################################################################################*/
+GfxResourceID Gfx_CreateIb2(int count, Gfx_FillIBFunc fillFunc, void* obj) {
+	return (void*)1; // don't need index buffers.. ?
+}
+
+void Gfx_BindIb(GfxResourceID ib) {
+}
+
+void Gfx_DeleteIb(GfxResourceID* ib) {
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Vertex buffers-----------------------------------------------------*
+*#########################################################################################################################*/
+static GfxResourceID Gfx_AllocStaticVb(VertexFormat fmt, int count) {
+	GX2RBuffer* buf = Mem_TryAllocCleared(1, sizeof(GX2RBuffer));
+	if (!buf) return NULL;
+	
+	buf->flags = GX2R_RESOURCE_BIND_VERTEX_BUFFER | GX2R_RESOURCE_USAGE_CPU_READ | GX2R_RESOURCE_USAGE_CPU_WRITE | GX2R_RESOURCE_USAGE_GPU_READ;
+	buf->elemSize  = strideSizes[fmt];
+	buf->elemCount = count;
+	
+	if (GX2RCreateBuffer(buf)) return buf;
+	// Something went wrong ?? TODO
+	Mem_Free(buf);
+	return NULL;
+}
+
+void Gfx_DeleteVb(GfxResourceID* vb) {
+	GX2RBuffer* buf = *vb;
+	if (!buf) return;
+	
+	GX2RDestroyBufferEx(buf, 0);
+	Mem_Free(buf);	
+	*vb = NULL;
+}
+
+void Gfx_BindVb(GfxResourceID vb) {
+	GX2RBuffer* buf = (GX2RBuffer*)vb;
+	GX2RSetAttributeBuffer(buf, 0, buf->elemSize, 0);
+	//GX2SetAttribBuffer(0, 
+}
+
+void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) {
+	GX2RBuffer* buf = (GX2RBuffer*)vb;
+	return GX2RLockBufferEx(buf, 0);
+}
+
+void Gfx_UnlockVb(GfxResourceID vb) {
+	GX2RBuffer* buf = (GX2RBuffer*)vb;
+	GX2RUnlockBufferEx(buf, 0);
+}
+
+
+/*########################################################################################################################*
+*--------------------------------------------------Dynamic vertex buffers-------------------------------------------------*
+*#########################################################################################################################*/
+static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
+	return Gfx_AllocStaticVb(fmt, maxVertices);
+}
+
+void Gfx_DeleteDynamicVb(GfxResourceID* vb) { Gfx_DeleteVb(vb); }
+
+void Gfx_BindDynamicVb(GfxResourceID vb)    { Gfx_BindVb(vb); }
+
+void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
+	return Gfx_LockVb(vb, fmt, count);
+}
+
+void Gfx_UnlockDynamicVb(GfxResourceID vb)  { Gfx_UnlockVb(vb); Gfx_BindVb(vb); }
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------Vertex rendering----------------------------------------------------*
+*#########################################################################################################################*/
+void Gfx_SetVertexFormat(VertexFormat fmt) {
+	if (fmt == gfx_format) return;
+	gfx_format = fmt;
+	gfx_stride = strideSizes[fmt];
+	
+	group = fmt == VERTEX_FORMAT_TEXTURED ? &textureShader : &colorShader;
+	GX2SetFetchShader(&group->fetchShader);
+	GX2SetVertexShader(group->vertexShader);
+	GX2SetPixelShader(group->pixelShader);
+}
+
+void Gfx_DrawVb_Lines(int verticesCount) {
+	BindPendingTexture();
+	GX2DrawEx(GX2_PRIMITIVE_MODE_LINES, verticesCount, 0, 1);
+}
+
+void Gfx_DrawVb_IndexedTris(int verticesCount) {
+	BindPendingTexture();
+	GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, verticesCount, 0, 1);
+}
+
+void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) {
+	BindPendingTexture();
+	GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, verticesCount, startVertex, 1);
+}
+
+void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) {
+	BindPendingTexture();
+	GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, verticesCount, startVertex, 1);
+}
+
+
+/*########################################################################################################################*
+*---------------------------------------------------------Matrices--------------------------------------------------------*
+*#########################################################################################################################*/
+static struct Matrix _view, _proj;
+void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) {
+	if (type == MATRIX_VIEW)       _view = *matrix;
+	if (type == MATRIX_PROJECTION) _proj = *matrix;
+	
+	// TODO dirty uniform
+	struct Matrix mvp __attribute__((aligned(64)));	
+	Matrix_Mul(&mvp, &_view, &_proj);
+	if (!group) return;
+	GX2SetVertexUniformReg(group->vertexShader->uniformVars[0].offset, 16, &mvp);
+}
+
+void Gfx_LoadIdentityMatrix(MatrixType type) {
+	Gfx_LoadMatrix(type, &Matrix_Identity);
+}
+
+void Gfx_EnableTextureOffset(float x, float y) {
+	// TODO
+}
+
+void Gfx_DisableTextureOffset(void) {
+	// TODO
+}
+
+void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float zNear, float zFar) {
+	// TODO verify this
+	*matrix = Matrix_Identity;
+
+	matrix->row1.x =  2.0f / width;
+	matrix->row2.y = -2.0f / height;
+	matrix->row3.z =  1.0f / (zNear - zFar);
+
+	matrix->row4.x = -1.0f;
+	matrix->row4.y =  1.0f;
+	matrix->row4.z = zNear / (zNear - zFar);
+}
+
+static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); }
+void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) {
+	// TODO verify this
+	float zNear = 0.1f;
+	float c = Cotangent(0.5f * fov);
+	*matrix = Matrix_Identity;
+
+	matrix->row1.x =  c / aspect;
+	matrix->row2.y =  c;
+	matrix->row3.z = zFar / (zNear - zFar);
+	matrix->row3.w = -1.0f;
+	matrix->row4.z = (zNear * zFar) / (zNear - zFar);
+	matrix->row4.w =  0.0f;
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------------Misc----------------------------------------------------------*
+*#########################################################################################################################*/
+cc_result Gfx_TakeScreenshot(struct Stream* output) {
+	return ERR_NOT_SUPPORTED;
+}
+
+void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) {
+	gfx_minFrameMs = minFrameMs;
+	gfx_vsync      = vsync;
+	
+	// TODO GX2SetSwapInterval(1);
+}
+
+void Gfx_BeginFrame(void) { 
+	uint32_t swapCount, flipCount;
+	OSTime lastFlip, lastVsync;
+	
+	for (int try = 0; try < 10; try++)
+	{
+		GX2GetSwapStatus(&swapCount, &flipCount, &lastFlip, &lastVsync);
+		if (flipCount >= swapCount) break;
+		GX2WaitForVsync(); // TODO vsync
+	}
+	
+	GX2ContextState* state = WHBGfxGetTVContextState();
+	GX2SetContextState(state);
+}
+
+void Gfx_ClearBuffers(GfxBuffers buffers) {
+	GX2ColorBuffer* buf = WHBGfxGetTVColourBuffer();
+	GX2DepthBuffer* dph = WHBGfxGetTVDepthBuffer();
+
+	if (buffers & GFX_BUFFER_COLOR) {
+		GX2ClearColor(buf, clearR, clearG, clearB, 1.0f);
+	}
+	if (buffers & GFX_BUFFER_DEPTH) {
+		GX2ClearDepthStencilEx(dph, 1.0f, 0, GX2_CLEAR_FLAGS_DEPTH | GX2_CLEAR_FLAGS_STENCIL);
+	}
+}
+
+static int drc_ticks;
+void Gfx_EndFrame(void) {
+	GX2ColorBuffer* buf;
+	
+	buf = WHBGfxGetTVColourBuffer();
+	GX2CopyColorBufferToScanBuffer(buf, GX2_SCAN_TARGET_TV);	
+
+	GX2ContextState* state = WHBGfxGetDRCContextState();
+	GX2SetContextState(state);
+	drc_ticks = (drc_ticks + 1) % 200;
+	buf = WHBGfxGetDRCColourBuffer();
+	GX2ClearColor(buf, drc_ticks / 200.0f, drc_ticks / 200.0f, drc_ticks / 200.0f, 1.0f);
+	GX2CopyColorBufferToScanBuffer(buf, GX2_SCAN_TARGET_DRC);	
+	
+	GX2SwapScanBuffers();
+	GX2Flush();
+	GX2DrawDone();
+	GX2SetTVEnable(TRUE);
+	GX2SetDRCEnable(TRUE);
+
+	if (gfx_minFrameMs) LimitFPS();
+}
+
+cc_bool Gfx_WarnIfNecessary(void) { return false; }
+
+void Gfx_GetApiInfo(cc_string* info) {
+	String_AppendConst(info, "-- Using Wii U --\n");
+	PrintMaxTextureInfo(info);
+}
+
+void Gfx_OnWindowResize(void) {
+
+}
+
+void Gfx_SetViewport(int x, int y, int w, int h) {
+   GX2SetViewport(x, y, w, h, 0.0f, 1.0f);
+   GX2SetScissor( x, y, w, h);
+}
+
+void Gfx_3DS_SetRenderScreen1(enum Screen3DS screen) {
+	GX2ContextState* tv_state  = WHBGfxGetTVContextState();
+	GX2ContextState* drc_state = WHBGfxGetDRCContextState(); // TODO
+	
+	GX2SetContextState(screen == TOP_SCREEN ? tv_state : drc_state);
+}
+#endif