From 4d04202dfc97c8b0957c74f5b6a670170791b42d Mon Sep 17 00:00:00 2001 From: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com> Date: Tue, 23 Aug 2022 13:05:52 +0200 Subject: [PATCH] wiiu: replace WhbGfx --- src/render/wiiu/SDL_render_wiiu.c | 19 +- src/render/wiiu/SDL_render_wiiu.h | 10 +- src/render/wiiu/SDL_rpresent_wiiu.c | 71 ++++--- src/render/wiiu/SDL_rqueue_wiiu.c | 6 +- src/render/wiiu/SDL_rtexture_wiiu.c | 7 + src/render/wiiu/SDL_shaders_wiiu.c | 2 +- src/render/wiiu/shaders/colorShader.vsh | 2 +- src/video/wiiu/SDL_wiiu_gfx_heap.c | 203 ++++++++++++++++++ src/video/wiiu/SDL_wiiu_gfx_heap.h | 53 +++++ src/video/wiiu/SDL_wiiuvideo.c | 265 +++++++++++++++++++++--- src/video/wiiu/SDL_wiiuvideo.h | 23 ++ 11 files changed, 585 insertions(+), 76 deletions(-) create mode 100644 src/video/wiiu/SDL_wiiu_gfx_heap.c create mode 100644 src/video/wiiu/SDL_wiiu_gfx_heap.h diff --git a/src/render/wiiu/SDL_render_wiiu.c b/src/render/wiiu/SDL_render_wiiu.c index f758a3405..1cd5485d7 100644 --- a/src/render/wiiu/SDL_render_wiiu.c +++ b/src/render/wiiu/SDL_render_wiiu.c @@ -167,6 +167,13 @@ void WIIU_SDL_CreateWindowTex(SDL_Renderer * renderer, SDL_Window * window) WIIU_SDL_CreateTexture(renderer, &data->windowTex); } +void WIIU_SDL_DestroyWindowTex(SDL_Renderer * renderer, SDL_Window * window) +{ + WIIU_RenderData *data = (WIIU_RenderData *) renderer->driverdata; + + WIIU_SDL_DestroyTexture(renderer, &data->windowTex); +} + int WIIU_SDL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) { WIIU_RenderData *data = (WIIU_RenderData *) renderer->driverdata; @@ -175,6 +182,9 @@ int WIIU_SDL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) WIIU_TextureData *tdata = (WIIU_TextureData *)((texture) ? texture->driverdata : data->windowTex.driverdata); + /* make sure we're using the correct renderer ctx */ + GX2SetContextState(data->ctx); + /* Wait for the texture rendering to finish */ WIIU_TextureCheckWaitRendering(data, tdata); @@ -189,11 +199,14 @@ int WIIU_SDL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) void WIIU_SDL_DestroyRenderer(SDL_Renderer * renderer) { WIIU_RenderData *data = (WIIU_RenderData *) renderer->driverdata; + WIIU_VideoData *videodata = (WIIU_VideoData *) SDL_GetVideoDevice()->driverdata; - GX2DrawDone(); + if (videodata->hasForeground) { + GX2DrawDone(); - WIIU_FreeRenderData(data); - WIIU_TextureDoneRendering(data); + WIIU_FreeRenderData(data); + WIIU_TextureDoneRendering(data); + } free(data->ctx); diff --git a/src/render/wiiu/SDL_render_wiiu.h b/src/render/wiiu/SDL_render_wiiu.h index f8b24f235..bb047f55d 100644 --- a/src/render/wiiu/SDL_render_wiiu.h +++ b/src/render/wiiu/SDL_render_wiiu.h @@ -31,6 +31,9 @@ #include "SDL_pixels.h" #include "SDL_shaders_wiiu.h" +#include "../../video/SDL_sysvideo.h" +#include "../../video/wiiu/SDL_wiiuvideo.h" + #include #include #include @@ -99,7 +102,7 @@ struct WIIU_TextureData GX2Sampler sampler; GX2Texture texture; GX2ColorBuffer cbuf; - int isRendering; + SDL_bool isRendering; }; /* Ask texture driver to allocate texture's memory from MEM1 */ @@ -136,6 +139,7 @@ void WIIU_SDL_DestroyRenderer(SDL_Renderer * renderer); /* Driver internal functions */ void WIIU_SDL_CreateWindowTex(SDL_Renderer * renderer, SDL_Window * window); +void WIIU_SDL_DestroyWindowTex(SDL_Renderer * renderer, SDL_Window * window); /* Utility/helper functions */ static inline GX2RBuffer * WIIU_AllocRenderData(WIIU_RenderData *r, GX2RBuffer buffer) @@ -166,7 +170,7 @@ static inline void WIIU_FreeRenderData(WIIU_RenderData *r) static inline void WIIU_TextureStartRendering(WIIU_RenderData *r, WIIU_TextureData *t) { WIIU_TextureDrawData *d = SDL_malloc(sizeof(WIIU_TextureDrawData)); - t->isRendering = 1; + t->isRendering = SDL_TRUE; d->texdata = t; d->next = r->listdraw; r->listdraw = d; @@ -177,7 +181,7 @@ static inline void WIIU_TextureDoneRendering(WIIU_RenderData *r) while (r->listdraw) { WIIU_TextureDrawData *d = r->listdraw; r->listdraw = r->listdraw->next; - d->texdata->isRendering = 0; + d->texdata->isRendering = SDL_FALSE; SDL_free(d); } } diff --git a/src/render/wiiu/SDL_rpresent_wiiu.c b/src/render/wiiu/SDL_rpresent_wiiu.c index 52fc71a97..d1a4839df 100644 --- a/src/render/wiiu/SDL_rpresent_wiiu.c +++ b/src/render/wiiu/SDL_rpresent_wiiu.c @@ -31,60 +31,63 @@ #include #include #include +#include +#include #include #include -#define SCREEN_WIDTH 1280 -#define SCREEN_HEIGHT 720 - void WIIU_SDL_RenderPresent(SDL_Renderer * renderer) { WIIU_RenderData *data = (WIIU_RenderData *) renderer->driverdata; WIIU_TextureData *tdata = (WIIU_TextureData *) data->windowTex.driverdata; Uint32 flags = SDL_GetWindowFlags(renderer->window); - int win_x, win_y, win_w, win_h; - - if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { - /* NOTE watch libwhb's source to ensure this call only does vsync */ - WHBGfxBeginRender(); - } - - /* Calculate and save positions TODO: make use of the window position */ - if (flags & SDL_WINDOW_FULLSCREEN) { - win_x = 0; - win_y = 0; - win_w = SCREEN_WIDTH; - win_h = SCREEN_HEIGHT; - } else { - /* Center */ - SDL_GetWindowSize(renderer->window, &win_w, &win_h); - win_x = (SCREEN_WIDTH - win_w) / 2; - win_y = (SCREEN_HEIGHT - win_h) / 2; - } /* Only render to TV if the window is *not* drc-only */ if (!(flags & SDL_WINDOW_WIIU_GAMEPAD_ONLY)) { - WHBGfxBeginRenderTV(); - GX2CopySurface(&tdata->texture.surface, 0, 0, &WHBGfxGetTVColourBuffer()->surface, 0, 0); - GX2SetContextState(data->ctx); - WHBGfxFinishRenderTV(); + GX2CopyColorBufferToScanBuffer(&tdata->cbuf, GX2_SCAN_TARGET_TV); } if (!(flags & SDL_WINDOW_WIIU_TV_ONLY)) { - WHBGfxBeginRenderDRC(); - GX2CopySurface(&tdata->texture.surface, 0, 0, &WHBGfxGetDRCColourBuffer()->surface, 0, 0); - GX2SetContextState(data->ctx); - WHBGfxFinishRenderDRC(); + GX2CopyColorBufferToScanBuffer(&tdata->cbuf, GX2_SCAN_TARGET_DRC); } - WHBGfxFinishRender(); + /* Swap buffers */ + GX2SwapScanBuffers(); + GX2Flush(); + + /* Restore SDL context state */ + GX2SetContextState(data->ctx); + + /* TV and DRC can now be enabled after the first frame was drawn */ + GX2SetTVEnable(TRUE); + GX2SetDRCEnable(TRUE); + + /* Wait for vsync */ + if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { + uint32_t swap_count, flip_count; + OSTime last_flip, last_vsync; + uint32_t wait_count = 0; + + while (true) { + GX2GetSwapStatus(&swap_count, &flip_count, &last_flip, &last_vsync); + + if (flip_count >= swap_count) { + break; + } + + if (wait_count >= 10) { + /* GPU timed out */ + break; + } + + wait_count++; + GX2WaitForVsync(); + } + } /* Free the list of render and draw data */ WIIU_FreeRenderData(data); WIIU_TextureDoneRendering(data); - - /* Restore SDL context state */ - GX2SetContextState(data->ctx); } #endif /* SDL_VIDEO_RENDER_WIIU */ diff --git a/src/render/wiiu/SDL_rqueue_wiiu.c b/src/render/wiiu/SDL_rqueue_wiiu.c index b8b7ee1f2..ce9bf9b29 100644 --- a/src/render/wiiu/SDL_rqueue_wiiu.c +++ b/src/render/wiiu/SDL_rqueue_wiiu.c @@ -351,12 +351,16 @@ int WIIU_SDL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, vo { WIIU_RenderData* data = (WIIU_RenderData*) renderer->driverdata; + /* make sure we're using the correct renderer ctx */ + WIIU_SDL_SetRenderTarget(renderer, renderer->target); + data->drawState.target = renderer->target; if (!data->drawState.target) { int w, h; SDL_GL_GetDrawableSize(renderer->window, &w, &h); if ((w != data->drawState.drawableWidth) || (h != data->drawState.drawableHeight)) { - data->drawState.viewportDirty = SDL_TRUE; // if the window dimensions changed, invalidate the current viewport, etc. + /* if the window dimensions changed, invalidate the current viewport, etc. */ + data->drawState.viewportDirty = SDL_TRUE; data->drawState.cliprectDirty = SDL_TRUE; data->drawState.drawableWidth = w; data->drawState.drawableHeight = h; diff --git a/src/render/wiiu/SDL_rtexture_wiiu.c b/src/render/wiiu/SDL_rtexture_wiiu.c index 7b507f6b8..eee69604a 100644 --- a/src/render/wiiu/SDL_rtexture_wiiu.c +++ b/src/render/wiiu/SDL_rtexture_wiiu.c @@ -198,6 +198,13 @@ void WIIU_SDL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) /* Wait for the texture rendering to finish */ WIIU_TextureCheckWaitRendering(data, tdata); + if (data->drawState.texture == texture) { + data->drawState.texture = NULL; + } + if (data->drawState.target == texture) { + data->drawState.target = NULL; + } + GX2RDestroySurfaceEx(&tdata->cbuf.surface, 0); GX2RDestroySurfaceEx(&tdata->texture.surface, 0); diff --git a/src/render/wiiu/SDL_shaders_wiiu.c b/src/render/wiiu/SDL_shaders_wiiu.c index 858410c0b..99814440f 100644 --- a/src/render/wiiu/SDL_shaders_wiiu.c +++ b/src/render/wiiu/SDL_shaders_wiiu.c @@ -38,7 +38,7 @@ void WIIU_SDL_CreateShaders(void) WHBGfxLoadGFDShaderGroup(colorShader, 0, colorShader_gsh); WHBGfxInitShaderAttribute(colorShader, "a_position", 0, 0, GX2_ATTRIB_FORMAT_FLOAT_32_32); - WHBGfxInitShaderAttribute(colorShader, "a_color", 0, 8, GX2_ATTRIB_FORMAT_FLOAT_32_32_32_32); + WHBGfxInitShaderAttribute(colorShader, "a_color", 0, 8, GX2_ATTRIB_FORMAT_UNORM_8_8_8_8); WHBGfxInitFetchShader(colorShader); WHBGfxLoadGFDShaderGroup(textureShader, 0, textureShader_gsh); diff --git a/src/render/wiiu/shaders/colorShader.vsh b/src/render/wiiu/shaders/colorShader.vsh index 525f70dcf..ee69cbd3a 100644 --- a/src/render/wiiu/shaders/colorShader.vsh +++ b/src/render/wiiu/shaders/colorShader.vsh @@ -2,7 +2,7 @@ ; $SPI_VS_OUT_CONFIG.VS_EXPORT_COUNT = 0 ; $NUM_SPI_VS_OUT_ID = 1 -; vColor +; v_color ; $SPI_VS_OUT_ID[0].SEMANTIC_0 = 0 ; C0 diff --git a/src/video/wiiu/SDL_wiiu_gfx_heap.c b/src/video/wiiu/SDL_wiiu_gfx_heap.c new file mode 100644 index 000000000..5e77367c7 --- /dev/null +++ b/src/video/wiiu/SDL_wiiu_gfx_heap.c @@ -0,0 +1,203 @@ +/* + Simple DirectMedia Layer + Copyright (c) 2015-present devkitPro, wut Authors + Copyright (C) 2022 GaryOderNichts + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_WIIU + +#include "SDL_wiiu_gfx_heap.h" + +#include +#include + +#include +#include +#include +#include + +#define FRM_HEAP_STATE_TAG 0x53444C32 // 'SDL2' + +static MEMHeapHandle GfxHeap_MEM1 = NULL; +static MEMHeapHandle GfxHeap_Foreground = NULL; + +int WIIU_GfxHeap_MEM1Init(void) +{ + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); + uint32_t size; + void *base; + + if (!MEMRecordStateForFrmHeap(heap, FRM_HEAP_STATE_TAG)) { + printf("%s: MEMRecordStateForFrmHeap failed\n", __FUNCTION__); + return -1; + } + + size = MEMGetAllocatableSizeForFrmHeapEx(heap, 4); + if (!size) { + printf("%s: MEMGetAllocatableSizeForFrmHeapEx == 0\n", __FUNCTION__); + return -1; + } + + base = MEMAllocFromFrmHeapEx(heap, size, 4); + if (!base) { + printf("%s: MEMAllocFromFrmHeapEx(heap, 0x%X, 4) failed\n", __FUNCTION__, size); + return -1; + } + + GfxHeap_MEM1 = MEMCreateExpHeapEx(base, size, 0); + if (!GfxHeap_MEM1) { + printf("%s: MEMCreateExpHeapEx(%p, 0x%X, 0) failed\n", __FUNCTION__, base, size); + return -1; + } + + return 0; +} + +int WIIU_GfxHeap_MEM1Destroy(void) +{ + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); + + if (GfxHeap_MEM1) { + MEMDestroyExpHeap(GfxHeap_MEM1); + GfxHeap_MEM1 = NULL; + } + + MEMFreeByStateToFrmHeap(heap, FRM_HEAP_STATE_TAG); + return 0; +} + +int WIIU_GfxHeap_ForegroundInit(void) +{ + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG); + uint32_t size; + void *base; + + size = MEMGetAllocatableSizeForFrmHeapEx(heap, 4); + if (!size) { + printf("%s: MEMAllocFromFrmHeapEx(heap, 0x%X, 4)\n", __FUNCTION__, size); + return -1; + } + + base = MEMAllocFromFrmHeapEx(heap, size, 4); + if (!base) { + printf("%s: MEMGetAllocatableSizeForFrmHeapEx == 0\n", __FUNCTION__); + return -1; + } + + GfxHeap_Foreground = MEMCreateExpHeapEx(base, size, 0); + if (!GfxHeap_Foreground) { + printf("%s: MEMCreateExpHeapEx(%p, 0x%X, 0)\n", __FUNCTION__, base, size); + return -1; + } + + return 0; +} + +int WIIU_GfxHeap_ForegroundDestroy(void) +{ + MEMHeapHandle foreground = MEMGetBaseHeapHandle(MEM_BASE_HEAP_FG); + + if (GfxHeap_Foreground) { + MEMDestroyExpHeap(GfxHeap_Foreground); + GfxHeap_Foreground = NULL; + } + + MEMFreeToFrmHeap(foreground, MEM_FRM_HEAP_FREE_ALL); + return 0; +} + +void *WIIU_GfxHeap_MEM1Alloc(uint32_t align, uint32_t size) +{ + void *block; + + if (!GfxHeap_MEM1) { + return NULL; + } + + if (align < 4) { + align = 4; + } + + block = MEMAllocFromExpHeapEx(GfxHeap_MEM1, size, align); + return block; +} + +void WIIU_GfxHeap_MEM1Free(void *block) +{ + if (!GfxHeap_MEM1) { + return; + } + + MEMFreeToExpHeap(GfxHeap_MEM1, block); +} + +void *WIIU_GfxHeap_ForegroundAlloc(uint32_t align, uint32_t size) +{ + void *block; + + if (!GfxHeap_Foreground) { + return NULL; + } + + if (align < 4) { + align = 4; + } + + block = MEMAllocFromExpHeapEx(GfxHeap_Foreground, size, align); + return block; +} + +void WIIU_GfxHeap_ForegroundFree(void *block) +{ + if (!GfxHeap_Foreground) { + return; + } + + MEMFreeToExpHeap(GfxHeap_Foreground, block); +} + +void *WIIU_GfxHeap_GX2RAlloc(GX2RResourceFlags flags, uint32_t size, uint32_t alignment) +{ + // Color, depth, scan buffers all belong in MEM1 + if ((flags & (GX2R_RESOURCE_BIND_COLOR_BUFFER + | GX2R_RESOURCE_BIND_DEPTH_BUFFER + | GX2R_RESOURCE_BIND_SCAN_BUFFER + | GX2R_RESOURCE_USAGE_FORCE_MEM1)) + && !(flags & GX2R_RESOURCE_USAGE_FORCE_MEM2)) { + return WIIU_GfxHeap_MEM1Alloc(alignment, size); + } else { + return memalign(alignment, size); + } +} + +void WIIU_GfxHeap_GX2RFree(GX2RResourceFlags flags, void *block) +{ + if ((flags & (GX2R_RESOURCE_BIND_COLOR_BUFFER + | GX2R_RESOURCE_BIND_DEPTH_BUFFER + | GX2R_RESOURCE_BIND_SCAN_BUFFER + | GX2R_RESOURCE_USAGE_FORCE_MEM1)) + && !(flags & GX2R_RESOURCE_USAGE_FORCE_MEM2)) { + return WIIU_GfxHeap_MEM1Free(block); + } else { + return free(block); + } +} + +#endif /* SDL_VIDEO_DRIVER_WIIU */ diff --git a/src/video/wiiu/SDL_wiiu_gfx_heap.h b/src/video/wiiu/SDL_wiiu_gfx_heap.h new file mode 100644 index 000000000..373913ada --- /dev/null +++ b/src/video/wiiu/SDL_wiiu_gfx_heap.h @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (c) 2015-present devkitPro, wut Authors + Copyright (C) 2022 GaryOderNichts + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef SDL_wiiu_gfx_heap_h +#define SDL_wiiu_gfx_heap_h + +#if SDL_VIDEO_DRIVER_WIIU + +#include + +int WIIU_GfxHeap_MEM1Init(void); + +int WIIU_GfxHeap_MEM1Destroy(void); + +int WIIU_GfxHeap_ForegroundInit(void); + +int WIIU_GfxHeap_ForegroundDestroy(void); + +void *WIIU_GfxHeap_MEM1Alloc(uint32_t align, uint32_t size); + +void WIIU_GfxHeap_MEM1Free(void *block); + +void *WIIU_GfxHeap_ForegroundAlloc(uint32_t align, uint32_t size); + +void WIIU_GfxHeap_ForegroundFree(void *block); + +void *WIIU_GfxHeap_GX2RAlloc(GX2RResourceFlags flags, uint32_t size, uint32_t alignment); + +void WIIU_GfxHeap_GX2RFree(GX2RResourceFlags flags, void *block); + +#endif /* SDL_VIDEO_DRIVER_WIIU */ + +#endif /* SDL_wiiu_gfx_heap_h */ diff --git a/src/video/wiiu/SDL_wiiuvideo.c b/src/video/wiiu/SDL_wiiuvideo.c index dc734023d..1edf51942 100644 --- a/src/video/wiiu/SDL_wiiuvideo.c +++ b/src/video/wiiu/SDL_wiiuvideo.c @@ -2,6 +2,7 @@ Simple DirectMedia Layer Copyright (C) 2018-2018 Ash Logan Copyright (C) 2018-2018 rw-r-r-0644 + Copyright (C) 2022 GaryOderNichts This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -20,13 +21,6 @@ 3. This notice may not be removed or altered from any source distribution. */ -/* This is basically just a stub at this point - all the magic happens in - * SDL_Render, and the textureframebuffer stuff in SDL_video.c. - * Potentially more could/should be done here, video modes and things. - * Some design work will need to go into the responsibilities of render - * vs video. - */ - #include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_WIIU @@ -37,81 +31,275 @@ #include "SDL_syswm.h" #include "SDL_loadso.h" #include "SDL_events.h" +#include "SDL_render.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_keyboard_c.h" +#include "../../events/SDL_events_c.h" #include "SDL_wiiuvideo.h" +#include "SDL_wiiu_gfx_heap.h" + +#include "../../render/wiiu/SDL_render_wiiu.h" #include -#include +#include +#include #include #include #include -static int WIIU_VideoInit(_THIS); -static int WIIU_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode); -static void WIIU_VideoQuit(_THIS); -static void WIIU_PumpEvents(_THIS); +#include +#include +#include +#include +#include +#include +#include -static int using_whb_proc = 0; +#define DRC_SCREEN_WIDTH 854 +#define DRC_SCREEN_HEIGHT 480 -#define SCREEN_WIDTH 1280 -#define SCREEN_HEIGHT 720 +static int WIIU_ForegroundAcquired(_THIS) +{ + WIIU_VideoData *videodata = (WIIU_VideoData *) _this->driverdata; + SDL_Window* window = _this->windows; + + videodata->hasForeground = SDL_TRUE; + + // initialize gfx heaps once in forground + if (WIIU_GfxHeap_ForegroundInit() != 0) { + return -1; + } + + if (WIIU_GfxHeap_MEM1Init() != 0) { + return -1; + } + + // allocate and set scanbuffers + videodata->tvScanBuffer = WIIU_GfxHeap_ForegroundAlloc(GX2_SCAN_BUFFER_ALIGNMENT, videodata->tvScanBufferSize); + if (!videodata->tvScanBuffer) { + return -1; + } + + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, videodata->tvScanBuffer, videodata->tvScanBufferSize); + GX2SetTVBuffer(videodata->tvScanBuffer, videodata->tvScanBufferSize, videodata->tvRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE); + + videodata->drcScanBuffer = WIIU_GfxHeap_ForegroundAlloc(GX2_SCAN_BUFFER_ALIGNMENT, videodata->drcScanBufferSize); + if (!videodata->drcScanBuffer) { + return -1; + } + + GX2Invalidate(GX2_INVALIDATE_MODE_CPU, videodata->drcScanBuffer, videodata->drcScanBufferSize); + GX2SetDRCBuffer(videodata->drcScanBuffer, videodata->drcScanBufferSize, videodata->drcRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE); + + // TODO recreate MEM1 surfaces for all windows + while (window) { + SDL_Renderer* renderer = SDL_GetRenderer(window); + //WIIU_SDL_CreateWindowTex(renderer, window); + + window = window->next; + } + + return 0; +} + +static int WIIU_ForegroundReleased(_THIS) +{ + WIIU_VideoData *videodata = (WIIU_VideoData *) _this->driverdata; + SDL_Window* window = _this->windows; + + // make sure the GPU is done drawing + GX2DrawDone(); + + if (videodata->tvScanBuffer) { + WIIU_GfxHeap_ForegroundFree(videodata->tvScanBuffer); + videodata->tvScanBuffer = NULL; + } + + if (videodata->drcScanBuffer) { + WIIU_GfxHeap_ForegroundFree(videodata->drcScanBuffer); + videodata->drcScanBuffer = NULL; + } + + // TODO destroy MEM1 surfaces for all windows + while (window) { + SDL_Renderer* renderer = SDL_GetRenderer(window); + //WIIU_SDL_DestroyWindowTex(renderer, window); + + window = window->next; + } + + WIIU_GfxHeap_MEM1Destroy(); + WIIU_GfxHeap_ForegroundDestroy(); + videodata->hasForeground = SDL_FALSE; + + return 0; +} static int WIIU_VideoInit(_THIS) { + WIIU_VideoData *videodata = (WIIU_VideoData *) _this->driverdata; + uint32_t unk; SDL_DisplayMode mode; + uint32_t* initAttribs; + // check if the user already set up procui or if we should handle it if (!ProcUIIsRunning()) { WHBProcInit(); - using_whb_proc = 1; + + videodata->handleProcUI = SDL_TRUE; } - WHBGfxInit(); - // add default mode (1280x720) - mode.format = SDL_PIXELFORMAT_RGBA8888; - mode.w = SCREEN_WIDTH; - mode.h = SCREEN_HEIGHT; - mode.refresh_rate = 60; - mode.driverdata = NULL; - if (SDL_AddBasicVideoDisplay(&mode) < 0) { - return -1; + // allocate command buffer pool + videodata->commandBufferPool = memalign(GX2_COMMAND_BUFFER_ALIGNMENT, GX2_COMMAND_BUFFER_SIZE); + if (!videodata->commandBufferPool) { + return SDL_OutOfMemory(); } - SDL_AddDisplayMode(&_this->displays[0], &mode); + + // initialize GX2 + initAttribs = (uint32_t[]) { + GX2_INIT_CMD_BUF_BASE, (uintptr_t) videodata->commandBufferPool, + GX2_INIT_CMD_BUF_POOL_SIZE, GX2_COMMAND_BUFFER_SIZE, + GX2_INIT_ARGC, 0, + GX2_INIT_ARGV, 0, + GX2_INIT_END + }; + GX2Init(initAttribs); + + // figure out the TV render mode and size + switch(GX2GetSystemTVScanMode()) { + case GX2_TV_SCAN_MODE_480I: + case GX2_TV_SCAN_MODE_480P: + videodata->tvRenderMode = GX2_TV_RENDER_MODE_WIDE_480P; + videodata->tvWidth = 854; + videodata->tvHeight = 480; + break; + case GX2_TV_SCAN_MODE_1080I: + case GX2_TV_SCAN_MODE_1080P: + videodata->tvRenderMode = GX2_TV_RENDER_MODE_WIDE_1080P; + videodata->tvWidth = 1920; + videodata->tvHeight = 1080; + break; + case GX2_TV_SCAN_MODE_720P: + default: + videodata->tvRenderMode = GX2_TV_RENDER_MODE_WIDE_720P; + videodata->tvWidth = 1280; + videodata->tvHeight = 720; + break; + } + + videodata->drcRenderMode = GX2GetSystemDRCScanMode(); + + // calculate the scanbuffer sizes + GX2CalcTVSize(videodata->tvRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &videodata->tvScanBufferSize, &unk); + GX2CalcDRCSize(videodata->drcRenderMode, GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8, GX2_BUFFERING_MODE_DOUBLE, &videodata->drcScanBufferSize, &unk); + + // set GX2R allocator for the gfx heap + GX2RSetAllocator(&WIIU_GfxHeap_GX2RAlloc, &WIIU_GfxHeap_GX2RFree); + + // register callbacks for acquiring and releasing foreground + ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, (ProcUICallback) WIIU_ForegroundAcquired, _this, 100); + ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, (ProcUICallback) WIIU_ForegroundReleased, _this, 100); + + // if this is running, the application is already in foreground so call the callback + if (WIIU_ForegroundAcquired(_this) != 0) { + free(videodata->commandBufferPool); + videodata->commandBufferPool = NULL; + return SDL_OutOfMemory(); + } + + GX2SetTVScale(videodata->tvWidth, videodata->tvHeight); + GX2SetDRCScale(DRC_SCREEN_WIDTH, DRC_SCREEN_HEIGHT); + + // add tv display + SDL_zero(mode); + mode.format = SDL_PIXELFORMAT_RGBA8888; + mode.w = videodata->tvWidth; + mode.h = videodata->tvHeight; + mode.refresh_rate = 60; + SDL_AddBasicVideoDisplay(&mode); + + // add drc display + SDL_zero(mode); + mode.format = SDL_PIXELFORMAT_RGBA8888; + mode.w = DRC_SCREEN_WIDTH; + mode.h = DRC_SCREEN_HEIGHT; + mode.refresh_rate = 60; + SDL_AddBasicVideoDisplay(&mode); return 0; } static void WIIU_VideoQuit(_THIS) { - WHBGfxShutdown(); - if (using_whb_proc) WHBProcShutdown(); + WIIU_VideoData *videodata = (WIIU_VideoData *) _this->driverdata; + + // if we're in foreground, destroy foreground data + if (videodata->hasForeground) { + WIIU_ForegroundReleased(_this); + } + + // shutdown GX2 and free command buffer + GX2Shutdown(); + + if (videodata->commandBufferPool) { + free(videodata->commandBufferPool); + videodata->commandBufferPool = NULL; + } + + if (videodata->handleProcUI) { + WHBProcShutdown(); + } } -static int WIIU_CreateSDLWindow(_THIS, SDL_Window *window) +static int WIIU_CreateSDLWindow(_THIS, SDL_Window * window) { - SDL_SetMouseFocus(window); - SDL_SetKeyboardFocus(window); + // focus the window + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); return 0; } -static int WIIU_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) +static void WIIU_SetWindowSize(_THIS, SDL_Window * window) +{ +} + +static void WIIU_DestroyWindow(_THIS, SDL_Window * window) +{ +} + +static void WIIU_GetDisplayModes(_THIS, SDL_VideoDisplay * display) +{ + // we currently only have one mode per display, which is the current one + SDL_AddDisplayMode(display, &display->current_mode); +} + +static int WIIU_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { return 0; } static void WIIU_PumpEvents(_THIS) { + WIIU_VideoData *videodata = (WIIU_VideoData *) _this->driverdata; + + if (videodata->handleProcUI) { + if (!WHBProcIsRunning()) { + SDL_SendQuit(); + } + } } static void WIIU_DeleteDevice(SDL_VideoDevice *device) { + SDL_free(device->driverdata); SDL_free(device); } static SDL_VideoDevice *WIIU_CreateDevice(int devindex) { SDL_VideoDevice *device; + WIIU_VideoData *videodata; device = (SDL_VideoDevice*) SDL_calloc(1, sizeof(SDL_VideoDevice)); if(!device) { @@ -119,11 +307,22 @@ static SDL_VideoDevice *WIIU_CreateDevice(int devindex) return NULL; } + videodata = (WIIU_VideoData*) SDL_calloc(1, sizeof(WIIU_VideoData)); + if(!videodata) { + SDL_OutOfMemory(); + return NULL; + } + + device->driverdata = videodata; + device->VideoInit = WIIU_VideoInit; device->VideoQuit = WIIU_VideoQuit; + device->CreateSDLWindow = WIIU_CreateSDLWindow; + device->SetWindowSize = WIIU_SetWindowSize; + device->DestroyWindow = WIIU_DestroyWindow; + device->GetDisplayModes = WIIU_GetDisplayModes; device->SetDisplayMode = WIIU_SetDisplayMode; device->PumpEvents = WIIU_PumpEvents; - device->CreateSDLWindow = WIIU_CreateSDLWindow; device->free = WIIU_DeleteDevice; diff --git a/src/video/wiiu/SDL_wiiuvideo.h b/src/video/wiiu/SDL_wiiuvideo.h index cca415bb0..a635012d9 100644 --- a/src/video/wiiu/SDL_wiiuvideo.h +++ b/src/video/wiiu/SDL_wiiuvideo.h @@ -2,6 +2,7 @@ Simple DirectMedia Layer Copyright (C) 2018-2018 Ash Logan Copyright (C) 2018-2018 Roberto Van Eeden + Copyright (C) 2022 GaryOderNichts This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -27,7 +28,29 @@ #if SDL_VIDEO_DRIVER_WIIU +#include +typedef struct WIIU_VideoData WIIU_VideoData; + +struct WIIU_VideoData +{ + // indicate if we're handling procui in SDL's events + SDL_bool handleProcUI; + + SDL_bool hasForeground; + + void *commandBufferPool; + + GX2TVRenderMode tvRenderMode; + uint32_t tvWidth; + uint32_t tvHeight; + void *tvScanBuffer; + uint32_t tvScanBufferSize; + + GX2DrcRenderMode drcRenderMode; + void *drcScanBuffer; + uint32_t drcScanBufferSize; +}; #endif /* SDL_VIDEO_DRIVER_WIIU */