Browse Source

Added support for external GPU textures to the GPU renderer

Sam Lantinga 6 days ago
parent
commit
941b0a8ea4
2 changed files with 103 additions and 53 deletions
  1. 41 24
      include/SDL3/SDL_render.h
  2. 62 29
      src/render/gpu/SDL_render_gpu.c

+ 41 - 24
include/SDL3/SDL_render.h

@@ -765,6 +765,19 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende
  *   VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL associated with the texture, if
  *   VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL associated with the texture, if
  *   you want to wrap an existing texture.
  *   you want to wrap an existing texture.
  *
  *
+ * With the GPU renderer:
+ *
+ * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER`: the SDL_GPUTexture associated with the texture, if you want to wrap an existing texture.
+ * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_NUMBER`: the SDL_GPUTexture
+ *   associated with the UV plane of an NV12 texture, if you want to wrap an
+ *   existing texture.
+ * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_U_NUMBER`: the SDL_GPUTexture
+ *   associated with the U plane of a YUV texture, if you want to wrap an
+ *   existing texture.
+ * - `SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_V_NUMBER`: the SDL_GPUTexture
+ *   associated with the V plane of a YUV texture, if you want to wrap an
+ *   existing texture.
+ *
  * \param renderer the rendering context.
  * \param renderer the rendering context.
  * \param props the properties to use.
  * \param props the properties to use.
  * \returns the created texture or NULL on failure; call SDL_GetError() for
  * \returns the created texture or NULL on failure; call SDL_GetError() for
@@ -783,30 +796,34 @@ extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromSurface(SDL_Rende
  */
  */
 extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props);
 extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props);
 
 
-#define SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER           "SDL.texture.create.colorspace"
-#define SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER               "SDL.texture.create.format"
-#define SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER               "SDL.texture.create.access"
-#define SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER                "SDL.texture.create.width"
-#define SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER               "SDL.texture.create.height"
-#define SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER             "SDL.texture.create.palette"
-#define SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT       "SDL.texture.create.SDR_white_point"
-#define SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT          "SDL.texture.create.HDR_headroom"
-#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER       "SDL.texture.create.d3d11.texture"
-#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER     "SDL.texture.create.d3d11.texture_u"
-#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER     "SDL.texture.create.d3d11.texture_v"
-#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_POINTER       "SDL.texture.create.d3d12.texture"
-#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER     "SDL.texture.create.d3d12.texture_u"
-#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_V_POINTER     "SDL.texture.create.d3d12.texture_v"
-#define SDL_PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER   "SDL.texture.create.metal.pixelbuffer"
-#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_NUMBER       "SDL.texture.create.opengl.texture"
-#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_UV_NUMBER    "SDL.texture.create.opengl.texture_uv"
-#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_U_NUMBER     "SDL.texture.create.opengl.texture_u"
-#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_V_NUMBER     "SDL.texture.create.opengl.texture_v"
-#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER    "SDL.texture.create.opengles2.texture"
-#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER "SDL.texture.create.opengles2.texture_uv"
-#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER  "SDL.texture.create.opengles2.texture_u"
-#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER  "SDL.texture.create.opengles2.texture_v"
-#define SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER       "SDL.texture.create.vulkan.texture"
+#define SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER               "SDL.texture.create.colorspace"
+#define SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER                   "SDL.texture.create.format"
+#define SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER                   "SDL.texture.create.access"
+#define SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER                    "SDL.texture.create.width"
+#define SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER                   "SDL.texture.create.height"
+#define SDL_PROP_TEXTURE_CREATE_PALETTE_POINTER                 "SDL.texture.create.palette"
+#define SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT           "SDL.texture.create.SDR_white_point"
+#define SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT              "SDL.texture.create.HDR_headroom"
+#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER           "SDL.texture.create.d3d11.texture"
+#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER         "SDL.texture.create.d3d11.texture_u"
+#define SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER         "SDL.texture.create.d3d11.texture_v"
+#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_POINTER           "SDL.texture.create.d3d12.texture"
+#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER         "SDL.texture.create.d3d12.texture_u"
+#define SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_V_POINTER         "SDL.texture.create.d3d12.texture_v"
+#define SDL_PROP_TEXTURE_CREATE_METAL_PIXELBUFFER_POINTER       "SDL.texture.create.metal.pixelbuffer"
+#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_NUMBER           "SDL.texture.create.opengl.texture"
+#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_UV_NUMBER        "SDL.texture.create.opengl.texture_uv"
+#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_U_NUMBER         "SDL.texture.create.opengl.texture_u"
+#define SDL_PROP_TEXTURE_CREATE_OPENGL_TEXTURE_V_NUMBER         "SDL.texture.create.opengl.texture_v"
+#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER        "SDL.texture.create.opengles2.texture"
+#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER     "SDL.texture.create.opengles2.texture_uv"
+#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER      "SDL.texture.create.opengles2.texture_u"
+#define SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER      "SDL.texture.create.opengles2.texture_v"
+#define SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER           "SDL.texture.create.vulkan.texture"
+#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER             "SDL.texture.create.gpu.texture"
+#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_POINTER          "SDL.texture.create.gpu.texture_uv"
+#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_U_POINTER           "SDL.texture.create.gpu.texture_u"
+#define SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_V_POINTER           "SDL.texture.create.gpu.texture_v"
 
 
 /**
 /**
  * Get the properties associated with a texture.
  * Get the properties associated with a texture.

+ 62 - 29
src/render/gpu/SDL_render_gpu.c

@@ -133,6 +133,7 @@ typedef struct GPU_PaletteData
 
 
 typedef struct GPU_TextureData
 typedef struct GPU_TextureData
 {
 {
+    bool external_texture;
     SDL_GPUTexture *texture;
     SDL_GPUTexture *texture;
     SDL_GPUTextureFormat format;
     SDL_GPUTextureFormat format;
     void *pixels;
     void *pixels;
@@ -142,11 +143,14 @@ typedef struct GPU_TextureData
 #ifdef SDL_HAVE_YUV
 #ifdef SDL_HAVE_YUV
     // YV12 texture support
     // YV12 texture support
     bool yuv;
     bool yuv;
+    bool external_texture_u;
+    bool external_texture_v;
     SDL_GPUTexture *textureU;
     SDL_GPUTexture *textureU;
     SDL_GPUTexture *textureV;
     SDL_GPUTexture *textureV;
 
 
     // NV12 texture support
     // NV12 texture support
     bool nv12;
     bool nv12;
+    bool external_texture_nv;
     SDL_GPUTexture *textureNV;
     SDL_GPUTexture *textureNV;
 #endif
 #endif
 } GPU_TextureData;
 } GPU_TextureData;
@@ -261,6 +265,12 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
     SDL_GPUTextureFormat format;
     SDL_GPUTextureFormat format;
     SDL_GPUTextureUsageFlags usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
     SDL_GPUTextureUsageFlags usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
 
 
+    data = (GPU_TextureData *)SDL_calloc(1, sizeof(*data));
+    if (!data) {
+        return false;
+    }
+    texture->internal = data;
+
     switch (texture->format) {
     switch (texture->format) {
     case SDL_PIXELFORMAT_INDEX8:
     case SDL_PIXELFORMAT_INDEX8:
     case SDL_PIXELFORMAT_YV12:
     case SDL_PIXELFORMAT_YV12:
@@ -292,11 +302,7 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
         return SDL_SetError("Texture format %s not supported by SDL_GPU",
         return SDL_SetError("Texture format %s not supported by SDL_GPU",
                             SDL_GetPixelFormatName(texture->format));
                             SDL_GetPixelFormatName(texture->format));
     }
     }
-
-    data = (GPU_TextureData *)SDL_calloc(1, sizeof(*data));
-    if (!data) {
-        return false;
-    }
+    data->format = format;
 
 
     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
         size_t size;
         size_t size;
@@ -326,7 +332,6 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
         usage |= SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
         usage |= SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
     }
     }
 
 
-    texture->internal = data;
     SDL_GPUTextureCreateInfo tci;
     SDL_GPUTextureCreateInfo tci;
     SDL_zero(tci);
     SDL_zero(tci);
     tci.format = format;
     tci.format = format;
@@ -336,11 +341,16 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
     tci.width = texture->w;
     tci.width = texture->w;
     tci.height = texture->h;
     tci.height = texture->h;
     tci.sample_count = SDL_GPU_SAMPLECOUNT_1;
     tci.sample_count = SDL_GPU_SAMPLECOUNT_1;
+    tci.props = create_props;
 
 
-    data->format = format;
-    data->texture = SDL_CreateGPUTexture(renderdata->device, &tci);
-    if (!data->texture) {
-        return false;
+    data->texture = SDL_GetPointerProperty(create_props, SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER, NULL);
+    if (data->texture) {
+        data->external_texture = true;
+    } else {
+        data->texture = SDL_CreateGPUTexture(renderdata->device, &tci);
+        if (!data->texture) {
+            return false;
+        }
     }
     }
 
 
     SDL_PropertiesID props = SDL_GetTextureProperties(texture);
     SDL_PropertiesID props = SDL_GetTextureProperties(texture);
@@ -354,15 +364,25 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
         tci.width = (tci.width + 1) / 2;
         tci.width = (tci.width + 1) / 2;
         tci.height = (tci.height + 1) / 2;
         tci.height = (tci.height + 1) / 2;
 
 
-        data->textureU = SDL_CreateGPUTexture(renderdata->device, &tci);
-        if (!data->textureU) {
-            return false;
+        data->textureU = SDL_GetPointerProperty(create_props, SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_U_POINTER, NULL);
+        if (data->textureU) {
+            data->external_texture_u = true;
+        } else {
+            data->textureU = SDL_CreateGPUTexture(renderdata->device, &tci);
+            if (!data->textureU) {
+                return false;
+            }
         }
         }
         SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER, data->textureU);
         SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER, data->textureU);
 
 
-        data->textureV = SDL_CreateGPUTexture(renderdata->device, &tci);
-        if (!data->textureV) {
-            return false;
+        data->textureV = SDL_GetPointerProperty(create_props, SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_V_POINTER, NULL);
+        if (data->textureV) {
+            data->external_texture_v = true;
+        } else {
+            data->textureV = SDL_CreateGPUTexture(renderdata->device, &tci);
+            if (!data->textureV) {
+                return false;
+            }
         }
         }
         SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER, data->textureU);
         SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER, data->textureU);
 
 
@@ -378,17 +398,22 @@ static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
 
 
         data->nv12 = true;
         data->nv12 = true;
 
 
-        tci.width = ((tci.width + 1) / 2);
-        tci.height = ((tci.height + 1) / 2);
-        if (texture->format == SDL_PIXELFORMAT_P010) {
-            tci.format = SDL_GPU_TEXTUREFORMAT_R16G16_UNORM;
+        data->textureNV = SDL_GetPointerProperty(create_props, SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_UV_POINTER, NULL);
+        if (data->textureNV) {
+            data->external_texture_nv = true;
         } else {
         } else {
-            tci.format = SDL_GPU_TEXTUREFORMAT_R8G8_UNORM;
-        }
+            tci.width = ((tci.width + 1) / 2);
+            tci.height = ((tci.height + 1) / 2);
+            if (texture->format == SDL_PIXELFORMAT_P010) {
+                tci.format = SDL_GPU_TEXTUREFORMAT_R16G16_UNORM;
+            } else {
+                tci.format = SDL_GPU_TEXTUREFORMAT_R8G8_UNORM;
+            }
 
 
-        data->textureNV = SDL_CreateGPUTexture(renderdata->device, &tci);
-        if (!data->textureNV) {
-            return false;
+            data->textureNV = SDL_CreateGPUTexture(renderdata->device, &tci);
+            if (!data->textureNV) {
+                return false;
+            }
         }
         }
         SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER, data->textureNV);
         SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER, data->textureNV);
 
 
@@ -1484,11 +1509,19 @@ static void GPU_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
         return;
         return;
     }
     }
 
 
-    SDL_ReleaseGPUTexture(renderdata->device, data->texture);
+    if (!data->external_texture) {
+        SDL_ReleaseGPUTexture(renderdata->device, data->texture);
+    }
 #ifdef SDL_HAVE_YUV
 #ifdef SDL_HAVE_YUV
-    SDL_ReleaseGPUTexture(renderdata->device, data->textureU);
-    SDL_ReleaseGPUTexture(renderdata->device, data->textureV);
-    SDL_ReleaseGPUTexture(renderdata->device, data->textureNV);
+    if (!data->external_texture_u) {
+        SDL_ReleaseGPUTexture(renderdata->device, data->textureU);
+    }
+    if (!data->external_texture_v) {
+        SDL_ReleaseGPUTexture(renderdata->device, data->textureV);
+    }
+    if (!data->external_texture_nv) {
+        SDL_ReleaseGPUTexture(renderdata->device, data->textureNV);
+    }
 #endif
 #endif
     SDL_free(data->pixels);
     SDL_free(data->pixels);
     SDL_free(data);
     SDL_free(data);