diff --git a/src/Backends/Rendering/WiiU.cpp b/src/Backends/Rendering/WiiU.cpp index f85de5a4..8330731c 100644 --- a/src/Backends/Rendering/WiiU.cpp +++ b/src/Backends/Rendering/WiiU.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -24,8 +25,8 @@ typedef struct RenderBackend_Surface { - bool is_screen; GX2Texture texture; + GX2ColorBuffer colour_buffer; unsigned int width; unsigned int height; unsigned char *lock_buffer; // TODO - Dumb @@ -44,128 +45,124 @@ static GX2RBuffer texture_coordinate_buffer; static GX2Sampler sampler; -RenderBackend_Surface *framebuffer; -static unsigned int framebuffer_width; -static unsigned int framebuffer_height; +static RenderBackend_Surface *framebuffer_surface; -static void StartFrameDraw(void) -{ - WHBGfxBeginRender(); - - // Draw to the gamepad - WHBGfxBeginRenderDRC(); - WHBGfxClearColor(0.0f, 0.0f, 0.0f, 1.0f); -} - -static void EndFrameDraw(void) -{ - WHBGfxFinishRenderDRC(); - - WHBGfxFinishRender(); -} +static GX2ContextState *gx2_context; RenderBackend_Surface* RenderBackend_Init(const char *window_title, int screen_width, int screen_height, bool fullscreen) { (void)window_title; (void)fullscreen; - framebuffer_width = screen_width; - framebuffer_height = screen_height; + WHBGfxInit(); - framebuffer = (RenderBackend_Surface*)malloc(sizeof(RenderBackend_Surface)); + // Initialise the shaders - if (framebuffer != NULL) + // Texture shader + if (WHBGfxLoadGFDShaderGroup(&texture_shader, 0, rtexture)) { - framebuffer->is_screen = true; + WHBGfxInitShaderAttribute(&texture_shader, "input_vertex_coordinates", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); + WHBGfxInitShaderAttribute(&texture_shader, "input_texture_coordinates", 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); + WHBGfxInitFetchShader(&texture_shader); - WHBGfxInit(); - - if (WHBGfxLoadGFDShaderGroup(&texture_shader, 0, rtexture)) + // Texture shader (with colour-key) + if (WHBGfxLoadGFDShaderGroup(&texture_colour_key_shader, 0, rtexture_colour_key)) { - WHBGfxInitShaderAttribute(&texture_shader, "input_vertex_coordinates", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); - WHBGfxInitShaderAttribute(&texture_shader, "input_texture_coordinates", 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); - WHBGfxInitFetchShader(&texture_shader); + WHBGfxInitShaderAttribute(&texture_colour_key_shader, "input_vertex_coordinates", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); + WHBGfxInitShaderAttribute(&texture_colour_key_shader, "input_texture_coordinates", 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); + WHBGfxInitFetchShader(&texture_colour_key_shader); - if (WHBGfxLoadGFDShaderGroup(&texture_colour_key_shader, 0, rtexture_colour_key)) + // Colour-fill shader + if (WHBGfxLoadGFDShaderGroup(&colour_fill_shader, 0, rcolour_fill)) { - WHBGfxInitShaderAttribute(&texture_colour_key_shader, "input_vertex_coordinates", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); - WHBGfxInitShaderAttribute(&texture_colour_key_shader, "input_texture_coordinates", 1, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); - WHBGfxInitFetchShader(&texture_colour_key_shader); + WHBGfxInitShaderAttribute(&colour_fill_shader, "input_vertex_coordinates", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); + WHBGfxInitFetchShader(&colour_fill_shader); - if (WHBGfxLoadGFDShaderGroup(&colour_fill_shader, 0, rcolour_fill)) + // Initialise vertex position buffer + vertex_position_buffer.flags = (GX2RResourceFlags)(GX2R_RESOURCE_BIND_VERTEX_BUFFER | + GX2R_RESOURCE_USAGE_CPU_READ | + GX2R_RESOURCE_USAGE_CPU_WRITE | + GX2R_RESOURCE_USAGE_GPU_READ); + vertex_position_buffer.elemSize = 2 * sizeof(float); + vertex_position_buffer.elemCount = 4; + GX2RCreateBuffer(&vertex_position_buffer); + + // Initialise texture coordinate buffer + texture_coordinate_buffer.flags = (GX2RResourceFlags)(GX2R_RESOURCE_BIND_VERTEX_BUFFER | + GX2R_RESOURCE_USAGE_CPU_READ | + GX2R_RESOURCE_USAGE_CPU_WRITE | + GX2R_RESOURCE_USAGE_GPU_READ); + texture_coordinate_buffer.elemSize = 2 * sizeof(float); + texture_coordinate_buffer.elemCount = 4; + GX2RCreateBuffer(&texture_coordinate_buffer); + + // Initialise sampler + GX2InitSampler(&sampler, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_POINT); + + // Create framebuffer surface + framebuffer_surface = RenderBackend_CreateSurface(screen_width, screen_height); + + if (framebuffer_surface != NULL) { - WHBGfxInitShaderAttribute(&colour_fill_shader, "input_vertex_coordinates", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); - WHBGfxInitFetchShader(&colour_fill_shader); + // Create a 'context' (this voodoo magic can be used to undo `GX2SetColorBuffer`, + // allowing us to draw to the screen once again). + gx2_context = (GX2ContextState*)aligned_alloc(GX2_CONTEXT_STATE_ALIGNMENT, sizeof(GX2ContextState)); + memset(gx2_context, 0, sizeof(GX2ContextState)); + GX2SetupContextStateEx(gx2_context, TRUE); + GX2SetContextState(gx2_context); - // Initialise vertex position buffer - vertex_position_buffer.flags = (GX2RResourceFlags)(GX2R_RESOURCE_BIND_VERTEX_BUFFER | - GX2R_RESOURCE_USAGE_CPU_READ | - GX2R_RESOURCE_USAGE_CPU_WRITE | - GX2R_RESOURCE_USAGE_GPU_READ); - vertex_position_buffer.elemSize = 2 * sizeof(float); - vertex_position_buffer.elemCount = 4; - GX2RCreateBuffer(&vertex_position_buffer); - - // Initialise texture coordinate buffer - texture_coordinate_buffer.flags = (GX2RResourceFlags)(GX2R_RESOURCE_BIND_VERTEX_BUFFER | - GX2R_RESOURCE_USAGE_CPU_READ | - GX2R_RESOURCE_USAGE_CPU_WRITE | - GX2R_RESOURCE_USAGE_GPU_READ); - texture_coordinate_buffer.elemSize = 2 * sizeof(float); - texture_coordinate_buffer.elemCount = 4; - GX2RCreateBuffer(&texture_coordinate_buffer); - - // Initialise sampler - GX2InitSampler(&sampler, GX2_TEX_CLAMP_MODE_CLAMP, GX2_TEX_XY_FILTER_MODE_POINT); - - { - // Disable depth-test (enabled by default for some reason) - GX2SetDepthOnlyControl(FALSE, FALSE, GX2_COMPARE_FUNC_ALWAYS); + // Disable depth-test (enabled by default for some reason) + GX2SetDepthOnlyControl(FALSE, FALSE, GX2_COMPARE_FUNC_ALWAYS); - // Enable blending - // GX2SetColorControl(GX2_LOGIC_OP_COPY, 0xFF, FALSE, TRUE); + // Enable blending + // GX2SetColorControl(GX2_LOGIC_OP_COPY, 0xFF, FALSE, TRUE); - // Set custom blending mode for pre-multiplied alpha - /* GX2SetBlendControl(GX2_RENDER_TARGET_0, - GX2_BLEND_MODE_ZERO, - GX2_BLEND_MODE_ONE, - GX2_BLEND_COMBINE_MODE_ADD, - TRUE, - GX2_BLEND_MODE_ZERO, - GX2_BLEND_MODE_ONE, - GX2_BLEND_COMBINE_MODE_ADD); - */ - // Do some binding + // Set custom blending mode for pre-multiplied alpha + /* GX2SetBlendControl(GX2_RENDER_TARGET_0, + GX2_BLEND_MODE_ZERO, + GX2_BLEND_MODE_ONE, + GX2_BLEND_COMBINE_MODE_ADD, + TRUE, + GX2_BLEND_MODE_ZERO, + GX2_BLEND_MODE_ONE, + GX2_BLEND_COMBINE_MODE_ADD); + */ + // Do some binding +/* + WHBGfxBeginRender(); - StartFrameDraw(); - - return framebuffer; - } - - GX2RDestroyBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); - GX2RDestroyBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); - - WHBGfxFreeShaderGroup(&colour_fill_shader); + // Draw to the gamepad + WHBGfxBeginRenderDRC(); + WHBGfxClearColor(0.0f, 0.0f, 0.0f, 1.0f); +*/ + return framebuffer_surface; } - WHBGfxFreeShaderGroup(&texture_colour_key_shader); + GX2RDestroyBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); + GX2RDestroyBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); + + WHBGfxFreeShaderGroup(&colour_fill_shader); } - WHBGfxFreeShaderGroup(&texture_shader); + WHBGfxFreeShaderGroup(&texture_colour_key_shader); } - WHBGfxShutdown(); - - free(framebuffer); + WHBGfxFreeShaderGroup(&texture_shader); } + WHBGfxShutdown(); + return NULL; } void RenderBackend_Deinit(void) { + free(gx2_context); + + RenderBackend_FreeSurface(framebuffer_surface); + GX2RDestroyBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); GX2RDestroyBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); @@ -174,15 +171,84 @@ void RenderBackend_Deinit(void) WHBGfxFreeShaderGroup(&texture_shader); WHBGfxShutdown(); - - free(framebuffer); } void RenderBackend_DrawScreen(void) { - EndFrameDraw(); + // Make sure the buffers aren't currently being used before we modify them + GX2DrawDone(); - StartFrameDraw(); + // Set buffer to full-screen + float *position_pointer = (float*)GX2RLockBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); + position_pointer[0] = -1.0f; + position_pointer[1] = -1.0f; + position_pointer[2] = 1.0f; + position_pointer[3] = -1.0f; + position_pointer[4] = 1.0f; + position_pointer[5] = 1.0f; + position_pointer[6] = -1.0f; + position_pointer[7] = 1.0f; + GX2RUnlockBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); + + // Set buffer to full-texture + float *texture_coordinate_pointer = (float*)GX2RLockBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); + texture_coordinate_pointer[0] = 0.0f; + texture_coordinate_pointer[1] = 1.0f; + texture_coordinate_pointer[2] = 1.0f; + texture_coordinate_pointer[3] = 1.0f; + texture_coordinate_pointer[4] = 1.0f; + texture_coordinate_pointer[5] = 0.0f; + texture_coordinate_pointer[6] = 0.0f; + texture_coordinate_pointer[7] = 0.0f; + GX2RUnlockBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); + + + WHBGfxBeginRender(); + + // Draw to the TV + WHBGfxBeginRenderTV(); + WHBGfxClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + // This might be needed? Not sure. +// GX2RInvalidateSurface(&framebuffer_surface->texture.surface, 0, (GX2RResourceFlags)0); + + GX2SetFetchShader(&texture_shader.fetchShader); + GX2SetVertexShader(texture_shader.vertexShader); + GX2SetPixelShader(texture_shader.pixelShader); + + GX2SetPixelSampler(&sampler, texture_shader.pixelShader->samplerVars[0].location); + GX2SetPixelTexture(&framebuffer_surface->texture, texture_shader.pixelShader->samplerVars[0].location); + GX2RSetAttributeBuffer(&vertex_position_buffer, 0, vertex_position_buffer.elemSize, 0); + GX2RSetAttributeBuffer(&texture_coordinate_buffer, 1, texture_coordinate_buffer.elemSize, 0); + + GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, 4, 0, 1); + + WHBGfxFinishRenderTV(); + + // Draw to the gamepad + WHBGfxBeginRenderDRC(); + WHBGfxClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + // This might be needed? Not sure. +// GX2RInvalidateSurface(&framebuffer_surface->texture.surface, 0, (GX2RResourceFlags)0); + + GX2SetFetchShader(&texture_shader.fetchShader); + GX2SetVertexShader(texture_shader.vertexShader); + GX2SetPixelShader(texture_shader.pixelShader); + + GX2SetPixelSampler(&sampler, texture_shader.pixelShader->samplerVars[0].location); + GX2SetPixelTexture(&framebuffer_surface->texture, texture_shader.pixelShader->samplerVars[0].location); + GX2RSetAttributeBuffer(&vertex_position_buffer, 0, vertex_position_buffer.elemSize, 0); + GX2RSetAttributeBuffer(&texture_coordinate_buffer, 1, texture_coordinate_buffer.elemSize, 0); + + GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, 4, 0, 1); + + WHBGfxFinishRenderDRC(); + + WHBGfxFinishRender(); + + // Do this or else the screen will never update. I wish I understood why. + GX2SetContextState(gx2_context); } RenderBackend_Surface* RenderBackend_CreateSurface(unsigned int width, unsigned int height) @@ -191,7 +257,6 @@ RenderBackend_Surface* RenderBackend_CreateSurface(unsigned int width, unsigned if (surface != NULL) { - surface->is_screen = false; surface->width = width; surface->height = height; @@ -210,11 +275,21 @@ RenderBackend_Surface* RenderBackend_CreateSurface(unsigned int width, unsigned GX2CalcSurfaceSizeAndAlignment(&surface->texture.surface); GX2InitTextureRegs(&surface->texture); + // Initialise colour buffer (needed so the texture can be drawn to) + memset(&surface->colour_buffer, 0, sizeof(surface->colour_buffer)); + surface->colour_buffer.surface = surface->texture.surface; + surface->colour_buffer.viewNumSlices = 1; + GX2InitColorBufferRegs(&surface->colour_buffer); + if (GX2RCreateSurface(&surface->texture.surface, (GX2RResourceFlags)(GX2R_RESOURCE_BIND_TEXTURE | GX2R_RESOURCE_BIND_COLOR_BUFFER | GX2R_RESOURCE_USAGE_CPU_WRITE | GX2R_RESOURCE_USAGE_CPU_READ | GX2R_RESOURCE_USAGE_GPU_WRITE | GX2R_RESOURCE_USAGE_GPU_READ))) { - return surface; + + if (GX2RCreateSurfaceUserMemory(&surface->colour_buffer.surface, (uint8_t*)surface->texture.surface.image, (uint8_t*)surface->texture.surface.mipmaps, surface->texture.surface.resourceFlags)) + return surface; + + GX2RDestroySurfaceEx(&surface->texture.surface, (GX2RResourceFlags)0); } free(surface); @@ -227,6 +302,7 @@ void RenderBackend_FreeSurface(RenderBackend_Surface *surface) { if (surface != NULL) { + GX2RDestroySurfaceEx(&surface->colour_buffer.surface, (GX2RResourceFlags)0); GX2RDestroySurfaceEx(&surface->texture.surface, (GX2RResourceFlags)0); free(surface); } @@ -293,11 +369,10 @@ void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBacke if (source_surface == NULL || destination_surface == NULL) return; - if (source_surface->is_screen || !destination_surface->is_screen) - return; - + // Make sure the buffers aren't currently being used before we modify them GX2DrawDone(); + // Set vertex position buffer const float destination_left = x; const float destination_top = y; const float destination_right = x + (rect->right - rect->left); @@ -312,18 +387,21 @@ void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBacke position_pointer[5] = destination_bottom; position_pointer[6] = destination_left; position_pointer[7] = destination_bottom; + for (unsigned int i = 0; i < 8; i += 2) { - position_pointer[i + 0] /= framebuffer_width; + position_pointer[i + 0] /= destination_surface->width; position_pointer[i + 0] *= 2.0f; position_pointer[i + 0] -= 1.0f; - position_pointer[i + 1] /= framebuffer_height; + position_pointer[i + 1] /= destination_surface->height; position_pointer[i + 1] *= -2.0f; position_pointer[i + 1] += 1.0f; } + GX2RUnlockBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); + // Set texture coordinate buffer float *texture_coordinate_pointer = (float*)GX2RLockBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); texture_coordinate_pointer[0] = rect->left / (float)source_surface->width; texture_coordinate_pointer[1] = rect->top / (float)source_surface->height; @@ -335,15 +413,26 @@ void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBacke texture_coordinate_pointer[7] = rect->bottom / (float)source_surface->height; GX2RUnlockBufferEx(&texture_coordinate_buffer, (GX2RResourceFlags)0); - GX2SetFetchShader(&texture_colour_key_shader.fetchShader); - GX2SetVertexShader(texture_colour_key_shader.vertexShader); - GX2SetPixelShader(texture_colour_key_shader.pixelShader); + // Draw to the selected texture, instead of the screen + GX2SetColorBuffer(&destination_surface->colour_buffer, GX2_RENDER_TARGET_0); + GX2SetViewport(0.0f, 0.0f, (float)destination_surface->colour_buffer.surface.width, (float)destination_surface->colour_buffer.surface.height, 0.0f, 1.0f); + GX2SetScissor(0, 0, destination_surface->colour_buffer.surface.width, destination_surface->colour_buffer.surface.height); - GX2SetPixelSampler(&sampler, texture_colour_key_shader.pixelShader->samplerVars[0].location); - GX2SetPixelTexture(&source_surface->texture, texture_colour_key_shader.pixelShader->samplerVars[0].location); + // Select shader + WHBGfxShaderGroup *shader = colour_key ? &texture_colour_key_shader : &texture_shader; + + // Bind it + GX2SetFetchShader(&shader->fetchShader); + GX2SetVertexShader(shader->vertexShader); + GX2SetPixelShader(shader->pixelShader); + + // Bind misc. data + GX2SetPixelSampler(&sampler, shader->pixelShader->samplerVars[0].location); + GX2SetPixelTexture(&source_surface->texture, shader->pixelShader->samplerVars[0].location); GX2RSetAttributeBuffer(&vertex_position_buffer, 0, vertex_position_buffer.elemSize, 0); GX2RSetAttributeBuffer(&texture_coordinate_buffer, 1, texture_coordinate_buffer.elemSize, 0); + // Draw GX2DrawEx(GX2_PRIMITIVE_MODE_QUADS, 4, 0, 1); } @@ -352,9 +441,7 @@ void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBacken if (surface == NULL) return; - if (!surface->is_screen) - return; - + // Make sure the buffers aren't currently being used before we modify them GX2DrawDone(); float *position_pointer = (float*)GX2RLockBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); @@ -368,16 +455,20 @@ void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBacken position_pointer[7] = rect->bottom; for (unsigned int i = 0; i < 8; i += 2) { - position_pointer[i + 0] /= framebuffer_width; + position_pointer[i + 0] /= surface->width; position_pointer[i + 0] *= 2.0f; position_pointer[i + 0] -= 1.0f; - position_pointer[i + 1] /= framebuffer_height; + position_pointer[i + 1] /= surface->height; position_pointer[i + 1] *= -2.0f; position_pointer[i + 1] += 1.0f; } GX2RUnlockBufferEx(&vertex_position_buffer, (GX2RResourceFlags)0); + GX2SetColorBuffer(&surface->colour_buffer, GX2_RENDER_TARGET_0); + GX2SetViewport(0, 0, (float)surface->colour_buffer.surface.width, (float)surface->colour_buffer.surface.height, 0.0f, 1.0f); + GX2SetScissor(0, 0, (float)surface->colour_buffer.surface.width, (float)surface->colour_buffer.surface.height); + float uniform_colours[4] = {red / 255.0f, green / 255.0f, blue / 255.0f, 1.0f}; GX2SetPixelUniformReg(colour_fill_shader.pixelShader->uniformVars[0].offset, 4, (uint32_t*)&uniform_colours);