1
0
Эх сурвалжийг харах

gdk: Render/GPU can call SuspendX, document when to call SuspendComplete

Ethan Lee 1 долоо хоног өмнө
parent
commit
5770e013c2

+ 28 - 4
VisualC-GDK/tests/testgdk/src/testgdk.cpp

@@ -291,9 +291,8 @@ static void DrawSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
     SDL_RenderPresent(renderer);
 }
 
-static void loop()
+static void update()
 {
-    int i;
     SDL_Event event;
 
     /* Check for events */
@@ -310,13 +309,31 @@ static void loop()
         SDLTest_CommonEvent(state, &event, &done);
 #endif
     }
+    fillerup();
+}
+
+static void draw()
+{
+    int i;
     for (i = 0; i < state->num_windows; ++i) {
         if (state->windows[i] == NULL) {
             continue;
         }
         DrawSprites(state->renderers[i], sprites[i]);
     }
-    fillerup();
+}
+
+static bool SDLCALL GDKEventWatch(void* userdata, SDL_Event* event)
+{
+    bool *suppressdraw = (bool *)userdata;
+    SDL_assert(suppressdraw != NULL);
+    if (event->type == SDL_EVENT_DID_ENTER_BACKGROUND) {
+        *suppressdraw = true;
+        SDL_GDKSuspendComplete();
+    } else if (event->type == SDL_EVENT_WILL_ENTER_FOREGROUND) {
+        *suppressdraw = false;
+    }
+    return true;
 }
 
 int main(int argc, char *argv[])
@@ -324,6 +341,7 @@ int main(int argc, char *argv[])
     int i;
     const char *icon = "icon.bmp";
     char *soundname = NULL;
+    bool suppressdraw = false;
 
     /* Initialize parameters */
     num_sprites = NUM_SPRITES;
@@ -390,6 +408,9 @@ int main(int argc, char *argv[])
         quit(2);
     }
 
+    /* By this point the renderers are made, so we can now add this watcher */
+    SDL_AddEventWatch(GDKEventWatch, &suppressdraw);
+
     /* Create the windows, initialize the renderers, and load the textures */
     sprites =
         (SDL_Texture **) SDL_malloc(state->num_windows * sizeof(*sprites));
@@ -441,7 +462,10 @@ int main(int argc, char *argv[])
     AddUserSilent();
 
     while (!done) {
-        loop();
+        update();
+        if (!suppressdraw) {
+            draw();
+        }
     }
 
     quit(0);

+ 7 - 0
include/SDL3/SDL_main.h

@@ -664,6 +664,13 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void);
 /**
  * Callback from the application to let the suspend continue.
  *
+ * When using SDL_Render or SDL_GPU, this function should be called _after_
+ * creating the `SDL_Renderer` or `SDL_GPUDevice`; this allows the timing of the
+ * D3D12 command queue suspension to execute in the correct order.
+ *
+ * If you're writing your own D3D12 renderer, this should be called after
+ * calling `ID3D12CommandQueue::SuspendX`.
+ *
  * This function is only needed for Xbox GDK support; all other platforms will
  * do nothing and set an "unsupported" error message.
  *

+ 20 - 0
src/render/direct3d12/SDL_render_d3d12.c

@@ -562,10 +562,26 @@ static HRESULT D3D12_IssueBatch(D3D12_RenderData *data)
     return result;
 }
 
+#ifdef SDL_PLATFORM_GDK
+static bool SDLCALL D3D12_GDKEventFilter(void* userdata, SDL_Event* event)
+{
+    D3D12_RenderData *data = (D3D12_RenderData *)userdata;
+    if (event->type == SDL_EVENT_DID_ENTER_BACKGROUND) {
+        data->commandQueue->SuspendX(0);
+    } else if (event->type == SDL_EVENT_WILL_ENTER_FOREGROUND) {
+        data->commandQueue->ResumeX();
+    }
+    return true;
+}
+#endif
+
 static void D3D12_DestroyRenderer(SDL_Renderer *renderer)
 {
     D3D12_RenderData *data = (D3D12_RenderData *)renderer->internal;
     if (data) {
+#ifdef SDL_PLATFORM_GDK
+        SDL_RemoveEventWatch(D3D12_GDKEventFilter, data);
+#endif
         D3D12_WaitForGPU(data);
         D3D12_ReleaseAll(renderer);
         SDL_free(data);
@@ -1112,6 +1128,10 @@ static HRESULT D3D12_CreateDeviceResources(SDL_Renderer *renderer)
     SDL_SetPointerProperty(props, SDL_PROP_RENDERER_D3D12_DEVICE_POINTER, data->d3dDevice);
     SDL_SetPointerProperty(props, SDL_PROP_RENDERER_D3D12_COMMAND_QUEUE_POINTER, data->commandQueue);
 
+#ifdef SDL_PLATFORM_GDK
+    SDL_AddEventWatch(D3D12_GDKEventFilter, data);
+#endif
+
 done:
     D3D_SAFE_RELEASE(d3dDevice);
     return result;

+ 21 - 0
src/render/gpu/SDL_render_gpu.c

@@ -1562,6 +1562,20 @@ static void GPU_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
     texture->internal = NULL;
 }
 
+#ifdef SDL_PLATFORM_GDK
+static bool SDLCALL GPU_GDKEventFilter(void *userdata, SDL_Event *event)
+{
+    GPU_RenderData *data = (GPU_RenderData *)userdata;
+    SDL_assert(!data->external_device);
+    if (event->type == SDL_EVENT_DID_ENTER_BACKGROUND) {
+        SDL_GDKSuspendGPU(data->device);
+    } else if (event->type == SDL_EVENT_WILL_ENTER_FOREGROUND) {
+        SDL_GDKResumeGPU(data->device);
+    }
+    return true;
+}
+#endif
+
 static void GPU_DestroyRenderer(SDL_Renderer *renderer)
 {
     GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
@@ -1595,6 +1609,9 @@ static void GPU_DestroyRenderer(SDL_Renderer *renderer)
     if (data->device) {
         GPU_ReleaseShaders(&data->shaders, data->device);
         if (!data->external_device) {
+#ifdef SDL_PLATFORM_GDK
+            SDL_RemoveEventWatch(GPU_GDKEventFilter, data);
+#endif
             SDL_DestroyGPUDevice(data->device);
         }
     }
@@ -1758,6 +1775,10 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
         if (!data->device) {
             return false;
         }
+
+#ifdef SDL_PLATFORM_GDK
+        SDL_AddEventWatch(GPU_GDKEventFilter, data);
+#endif
     }
 
     if (!GPU_InitShaders(&data->shaders, data->device)) {