Browse Source

GPU: Rework MSAA (#10859)

Caleb Cornett 11 months ago
parent
commit
9416917353

+ 27 - 12
include/SDL3/SDL_gpu.h

@@ -282,8 +282,10 @@ typedef enum SDL_GPULoadOp
  */
 typedef enum SDL_GPUStoreOp
 {
-    SDL_GPU_STOREOP_STORE,     /**< The contents generated during the render pass will be written to memory. */
-    SDL_GPU_STOREOP_DONT_CARE  /**< The contents generated during the render pass are not needed and may be discarded. The contents will be undefined. */
+    SDL_GPU_STOREOP_STORE,             /**< The contents generated during the render pass will be written to memory. */
+    SDL_GPU_STOREOP_DONT_CARE,         /**< The contents generated during the render pass are not needed and may be discarded. The contents will be undefined. */
+    SDL_GPU_STOREOP_RESOLVE,           /**< The multisample contents generated during the render pass will be resolved to a non-multisample texture. The contents in the multisample texture may then be discarded and will be undefined. */
+    SDL_GPU_STOREOP_RESOLVE_AND_STORE  /**< The multisample contents generated during the render pass will be resolved to a non-multisample texture. The contents in the multisample texture will be written to memory. */
 } SDL_GPUStoreOp;
 
 /**
@@ -1499,7 +1501,8 @@ typedef struct SDL_GPUComputePipelineCreateInfo
  * The load_op field determines what is done with the texture at the beginning
  * of the render pass.
  *
- * - LOAD: Loads the data currently in the texture.
+ * - LOAD: Loads the data currently in the texture. Not recommended for
+ *   multisample textures as it requires significant memory bandwidth.
  * - CLEAR: Clears the texture to a single color.
  * - DONT_CARE: The driver will do whatever it wants with the texture memory.
  *   This is a good option if you know that every single pixel will be touched
@@ -1508,9 +1511,16 @@ typedef struct SDL_GPUComputePipelineCreateInfo
  * The store_op field determines what is done with the color results of the
  * render pass.
  *
- * - STORE: Stores the results of the render pass in the texture.
+ * - STORE: Stores the results of the render pass in the texture. Not recommended
+ *   for multisample textures as it requires significant memory bandwidth.
  * - DONT_CARE: The driver will do whatever it wants with the texture memory.
  *   This is often a good option for depth/stencil textures.
+ * - RESOLVE: Resolves a multisample texture into resolve_texture, which must have
+ *   a sample count of 1. Then the driver may discard the multisample texture memory.
+ *   This is the most performant method of resolving a multisample target.
+ * - RESOLVE_AND_STORE: Resolves a multisample texture into the resolve_texture,
+ *   which must have a sample count of 1. Then the driver stores the multisample
+ *   texture's contents. Not recommended as it requires significant memory bandwidth.
  *
  * \since This struct is available since SDL 3.0.0
  *
@@ -1518,16 +1528,19 @@ typedef struct SDL_GPUComputePipelineCreateInfo
  */
 typedef struct SDL_GPUColorTargetInfo
 {
-    SDL_GPUTexture *texture;      /**< The texture that will be used as a color target by a render pass. */
-    Uint32 mip_level;             /**< The mip level to use as a color target. */
-    Uint32 layer_or_depth_plane;  /**< The layer index or depth plane to use as a color target. This value is treated as a layer index on 2D array and cube textures, and as a depth plane on 3D textures. */
-    SDL_FColor clear_color;       /**< The color to clear the color target to at the start of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */
-    SDL_GPULoadOp load_op;        /**< What is done with the contents of the color target at the beginning of the render pass. */
-    SDL_GPUStoreOp store_op;      /**< What is done with the results of the render pass. */
-    SDL_bool cycle;               /**< SDL_TRUE cycles the texture if the texture is bound and load_op is not LOAD */
+    SDL_GPUTexture *texture;         /**< The texture that will be used as a color target by a render pass. */
+    Uint32 mip_level;                /**< The mip level to use as a color target. */
+    Uint32 layer_or_depth_plane;     /**< The layer index or depth plane to use as a color target. This value is treated as a layer index on 2D array and cube textures, and as a depth plane on 3D textures. */
+    SDL_FColor clear_color;          /**< The color to clear the color target to at the start of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */
+    SDL_GPULoadOp load_op;           /**< What is done with the contents of the color target at the beginning of the render pass. */
+    SDL_GPUStoreOp store_op;         /**< What is done with the results of the render pass. */
+    SDL_GPUTexture *resolve_texture; /**< The texture that will receive the results of a multisample resolve operation. Ignored if a RESOLVE* store_op is not used. */
+    Uint32 resolve_mip_level;        /**< The mip level of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used. */
+    Uint32 resolve_layer;            /**< The layer index of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used. */
+    SDL_bool cycle;                  /**< SDL_TRUE cycles the texture if the texture is bound and load_op is not LOAD */
+    SDL_bool cycle_resolve_texture;  /**< SDL_TRUE cycles the resolve texture if the resolve texture is bound. Ignored if a RESOLVE* store_op is not used. */
     Uint8 padding1;
     Uint8 padding2;
-    Uint8 padding3;
 } SDL_GPUColorTargetInfo;
 
 /**
@@ -1568,6 +1581,8 @@ typedef struct SDL_GPUColorTargetInfo
  *   This is often a good option for depth/stencil textures that don't need to
  *   be reused again.
  *
+ * Note that depth/stencil targets do not support multisample resolves.
+ *
  * \since This struct is available since SDL 3.0.0
  *
  * \sa SDL_BeginGPURenderPass

+ 54 - 12
src/gpu/SDL_gpu.c

@@ -867,6 +867,13 @@ SDL_GPUTexture *SDL_CreateGPUTexture(
             SDL_assert_release(!"For any texture: usage cannot contain both GRAPHICS_STORAGE_READ and SAMPLER");
             failed = true;
         }
+        if (createinfo->sample_count > 1 && (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER |
+                                                                  SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ |
+                                                                  SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ |
+                                                                  SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE))) {
+            SDL_assert_release(!"For multisample textures: usage cannot contain SAMPLER or STORAGE flags");
+            failed = true;
+        }
         if (IsDepthFormat(createinfo->format) && (createinfo->usage & ~(SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER))) {
             SDL_assert_release(!"For depth textures: usage cannot contain any flags except for DEPTH_STENCIL_TARGET and SAMPLER");
             failed = true;
@@ -945,16 +952,10 @@ SDL_GPUTexture *SDL_CreateGPUTexture(
                     SDL_assert_release(!"For array textures: usage must not contain DEPTH_STENCIL_TARGET");
                     failed = true;
                 }
-                if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
-                    SDL_assert_release(!"For array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
-                    failed = true;
-                }
-            } else {
-                // 2D Texture Validation
-                if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->num_levels > 1) {
-                    SDL_assert_release(!"For 2D textures: if sample_count is >= SDL_GPU_SAMPLECOUNT_1, then num_levels must be 1");
-                    failed = true;
-                }
+            }
+            if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->num_levels > 1) {
+                SDL_assert_release(!"For 2D multisample textures: num_levels must be 1");
+                failed = true;
             }
             if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_2D, createinfo->usage)) {
                 SDL_assert_release(!"For 2D textures: the format is unsupported for the given usage");
@@ -1347,13 +1348,50 @@ SDL_GPURenderPass *SDL_BeginGPURenderPass(
         CHECK_ANY_PASS_IN_PROGRESS("Cannot begin render pass during another pass!", NULL)
 
         for (Uint32 i = 0; i < num_color_targets; i += 1) {
+            TextureCommonHeader *textureHeader = (TextureCommonHeader *)color_target_infos[i].texture;
+
             if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
                 SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
             }
+
+            if (color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE || color_target_infos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
+                if (color_target_infos[i].resolve_texture == NULL) {
+                    SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but resolve_texture is NULL!");
+                } else {
+                    TextureCommonHeader *resolveTextureHeader = (TextureCommonHeader *)color_target_infos[i].resolve_texture;
+                    if (textureHeader->info.sample_count == SDL_GPU_SAMPLECOUNT_1) {
+                        SDL_assert_release(!"Store op is RESOLVE or RESOLVE_AND_STORE but texture is not multisample!");
+                    }
+                    if (resolveTextureHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
+                        SDL_assert_release(!"Resolve texture must have a sample count of 1!");
+                    }
+                    if (resolveTextureHeader->info.format != textureHeader->info.format) {
+                        SDL_assert_release(!"Resolve texture must have the same format as its corresponding color target!");
+                    }
+                    if (resolveTextureHeader->info.type == SDL_GPU_TEXTURETYPE_3D) {
+                        SDL_assert_release(!"Resolve texture must not be of TEXTURETYPE_3D!");
+                    }
+                }
+            }
         }
 
-        if (depth_stencil_target_info != NULL && depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD)) {
-            SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
+        if (depth_stencil_target_info != NULL) {
+
+            TextureCommonHeader *textureHeader = (TextureCommonHeader *)depth_stencil_target_info->texture;
+            if (!(textureHeader->info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
+                SDL_assert_release(!"Depth target must have been created with the DEPTH_STENCIL_TARGET usage flag!");
+            }
+
+            if (depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->stencil_load_op == SDL_GPU_LOADOP_LOAD)) {
+                SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
+            }
+
+            if (depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE ||
+                depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE ||
+                depth_stencil_target_info->store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE ||
+                depth_stencil_target_info->stencil_store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
+                SDL_assert_release(!"RESOLVE store ops are not supported for depth-stencil targets!");
+            }
         }
     }
 
@@ -2397,6 +2435,10 @@ void SDL_BlitGPUTexture(
             SDL_assert_release(!"Blit destination texture must be non-NULL");
             return; // attempting to proceed will crash
         }
+        if (srcHeader->info.sample_count != SDL_GPU_SAMPLECOUNT_1) {
+            SDL_assert_release(!"Blit source texture must have a sample count of 1");
+            failed = true;
+        }
         if ((srcHeader->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) == 0) {
             SDL_assert_release(!"Blit source texture must be created with the SAMPLER usage flag");
             failed = true;

+ 53 - 105
src/gpu/d3d11/SDL_gpu_d3d11.c

@@ -438,9 +438,6 @@ typedef struct D3D11TextureSubresource
 
     ID3D11UnorderedAccessView *uav;                 // NULL if not a storage texture
     ID3D11DepthStencilView *depthStencilTargetView; // NULL if not a depth stencil target
-
-    ID3D11Resource *msaaHandle;             // NULL if not using MSAA
-    ID3D11RenderTargetView *msaaTargetView; // NULL if not an MSAA color target
 } D3D11TextureSubresource;
 
 struct D3D11Texture
@@ -637,12 +634,8 @@ typedef struct D3D11CommandBuffer
     D3D11GraphicsPipeline *graphicsPipeline;
     Uint8 stencilRef;
     SDL_FColor blendConstants;
-
-    // Render Pass MSAA resolve
-    D3D11Texture *colorTargetResolveTexture[MAX_COLOR_TARGET_BINDINGS];
-    Uint32 colorTargetResolveSubresourceIndex[MAX_COLOR_TARGET_BINDINGS];
-    ID3D11Resource *colorTargetMsaaHandle[MAX_COLOR_TARGET_BINDINGS];
-    DXGI_FORMAT colorTargetMsaaFormat[MAX_COLOR_TARGET_BINDINGS];
+    D3D11TextureSubresource *colorTargetSubresources[MAX_COLOR_TARGET_BINDINGS];
+    D3D11TextureSubresource *colorResolveSubresources[MAX_COLOR_TARGET_BINDINGS];
 
     // Compute Pass
     D3D11ComputePipeline *computePipeline;
@@ -1090,14 +1083,6 @@ static void D3D11_INTERNAL_DestroyTexture(D3D11Texture *d3d11Texture)
     }
 
     for (Uint32 subresourceIndex = 0; subresourceIndex < d3d11Texture->subresourceCount; subresourceIndex += 1) {
-        if (d3d11Texture->subresources[subresourceIndex].msaaHandle != NULL) {
-            ID3D11Resource_Release(d3d11Texture->subresources[subresourceIndex].msaaHandle);
-        }
-
-        if (d3d11Texture->subresources[subresourceIndex].msaaTargetView != NULL) {
-            ID3D11RenderTargetView_Release(d3d11Texture->subresources[subresourceIndex].msaaTargetView);
-        }
-
         if (d3d11Texture->subresources[subresourceIndex].colorTargetViews != NULL) {
             for (Uint32 depthIndex = 0; depthIndex < d3d11Texture->subresources[subresourceIndex].depth; depthIndex += 1) {
                 ID3D11RenderTargetView_Release(d3d11Texture->subresources[subresourceIndex].colorTargetViews[depthIndex]);
@@ -1933,8 +1918,8 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
         desc2D.Format = format;
         desc2D.MipLevels = createInfo->num_levels;
         desc2D.MiscFlags = 0;
-        desc2D.SampleDesc.Count = 1;
-        desc2D.SampleDesc.Quality = 0;
+        desc2D.SampleDesc.Count = SDLToD3D11_SampleCount[createInfo->sample_count];
+        desc2D.SampleDesc.Quality = isMultisample ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0;
         desc2D.Usage = isStaging ? D3D11_USAGE_STAGING : D3D11_USAGE_DEFAULT;
 
         if (createInfo->type == SDL_GPU_TEXTURETYPE_CUBE || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
@@ -2067,54 +2052,10 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
             d3d11Texture->subresources[subresourceIndex].colorTargetViews = NULL;
             d3d11Texture->subresources[subresourceIndex].uav = NULL;
             d3d11Texture->subresources[subresourceIndex].depthStencilTargetView = NULL;
-            d3d11Texture->subresources[subresourceIndex].msaaHandle = NULL;
-            d3d11Texture->subresources[subresourceIndex].msaaTargetView = NULL;
-
-            if (isMultisample) {
-                D3D11_TEXTURE2D_DESC desc2D;
-
-                if (isColorTarget) {
-                    desc2D.BindFlags = D3D11_BIND_RENDER_TARGET;
-                } else if (isDepthStencil) {
-                    desc2D.BindFlags = D3D11_BIND_DEPTH_STENCIL;
-                }
-
-                desc2D.Width = createInfo->width;
-                desc2D.Height = createInfo->height;
-                desc2D.ArraySize = 1;
-                desc2D.CPUAccessFlags = 0;
-                desc2D.Format = format;
-                desc2D.MipLevels = 1;
-                desc2D.MiscFlags = 0;
-                desc2D.SampleDesc.Count = SDLToD3D11_SampleCount[createInfo->sample_count];
-                desc2D.SampleDesc.Quality = (UINT)D3D11_STANDARD_MULTISAMPLE_PATTERN;
-                desc2D.Usage = D3D11_USAGE_DEFAULT;
-
-                res = ID3D11Device_CreateTexture2D(
-                    renderer->device,
-                    &desc2D,
-                    NULL,
-                    (ID3D11Texture2D **)&d3d11Texture->subresources[subresourceIndex].msaaHandle);
-                ERROR_CHECK_RETURN("Could not create MSAA texture!", NULL);
-
-                if (!isDepthStencil) {
-                    D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
-
-                    rtvDesc.Format = format;
-                    rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
-
-                    res = ID3D11Device_CreateRenderTargetView(
-                        renderer->device,
-                        d3d11Texture->subresources[subresourceIndex].msaaHandle,
-                        &rtvDesc,
-                        &d3d11Texture->subresources[subresourceIndex].msaaTargetView);
-                    ERROR_CHECK_RETURN("Could not create MSAA RTV!", NULL);
-                }
-            }
 
             if (isDepthStencil) {
-                D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
 
+                D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
                 dsvDesc.Format = SDLToD3D11_TextureFormat[createInfo->format];
                 dsvDesc.Flags = 0;
 
@@ -2127,31 +2068,42 @@ static D3D11Texture *D3D11_INTERNAL_CreateTexture(
 
                 res = ID3D11Device_CreateDepthStencilView(
                     renderer->device,
-                    isMultisample ? d3d11Texture->subresources[subresourceIndex].msaaHandle : d3d11Texture->handle,
+                    d3d11Texture->handle,
                     &dsvDesc,
                     &d3d11Texture->subresources[subresourceIndex].depthStencilTargetView);
                 ERROR_CHECK_RETURN("Could not create DSV!", NULL);
+
             } else if (isColorTarget) {
+
                 d3d11Texture->subresources[subresourceIndex].colorTargetViews = SDL_calloc(depth, sizeof(ID3D11RenderTargetView *));
 
                 for (Uint32 depthIndex = 0; depthIndex < depth; depthIndex += 1) {
                     D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
-
                     rtvDesc.Format = SDLToD3D11_TextureFormat[createInfo->format];
 
-                    if (createInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
-                        rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
-                        rtvDesc.Texture2DArray.MipSlice = levelIndex;
-                        rtvDesc.Texture2DArray.FirstArraySlice = layerIndex;
-                        rtvDesc.Texture2DArray.ArraySize = 1;
-                    } else if (createInfo->type == SDL_GPU_TEXTURETYPE_3D) {
-                        rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
-                        rtvDesc.Texture3D.MipSlice = levelIndex;
-                        rtvDesc.Texture3D.FirstWSlice = depthIndex;
-                        rtvDesc.Texture3D.WSize = 1;
+                    if (isMultisample) {
+                        if (createInfo->type == SDL_GPU_TEXTURETYPE_2D) {
+                            rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
+                        } else if (createInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
+                            rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
+                            rtvDesc.Texture2DMSArray.FirstArraySlice = layerIndex;
+                            rtvDesc.Texture2DMSArray.ArraySize = 1;
+                        }
                     } else {
-                        rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
-                        rtvDesc.Texture2D.MipSlice = levelIndex;
+                        if (createInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE || createInfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
+                            rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+                            rtvDesc.Texture2DArray.MipSlice = levelIndex;
+                            rtvDesc.Texture2DArray.FirstArraySlice = layerIndex;
+                            rtvDesc.Texture2DArray.ArraySize = 1;
+                        } else if (createInfo->type == SDL_GPU_TEXTURETYPE_3D) {
+                            rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
+                            rtvDesc.Texture3D.MipSlice = levelIndex;
+                            rtvDesc.Texture3D.FirstWSlice = depthIndex;
+                            rtvDesc.Texture3D.WSize = 1;
+                        } else {
+                            rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+                            rtvDesc.Texture2D.MipSlice = levelIndex;
+                        }
                     }
 
                     res = ID3D11Device_CreateRenderTargetView(
@@ -3238,10 +3190,8 @@ static SDL_GPUCommandBuffer *D3D11_AcquireCommandBuffer(
     commandBuffer->blendConstants.a = 1.0f;
     commandBuffer->computePipeline = NULL;
     for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) {
-        commandBuffer->colorTargetResolveTexture[i] = NULL;
-        commandBuffer->colorTargetResolveSubresourceIndex[i] = 0;
-        commandBuffer->colorTargetMsaaHandle[i] = NULL;
-        commandBuffer->colorTargetMsaaFormat[i] = DXGI_FORMAT_UNKNOWN;
+        commandBuffer->colorTargetSubresources[i] = NULL;
+        commandBuffer->colorResolveSubresources[i] = NULL;
     }
 
     for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
@@ -3507,10 +3457,8 @@ static void D3D11_BeginRenderPass(
 
     // Clear the bound targets for the current command buffer
     for (Uint32 i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) {
-        d3d11CommandBuffer->colorTargetResolveTexture[i] = NULL;
-        d3d11CommandBuffer->colorTargetResolveSubresourceIndex[i] = 0;
-        d3d11CommandBuffer->colorTargetMsaaHandle[i] = NULL;
-        d3d11CommandBuffer->colorTargetMsaaFormat[i] = DXGI_FORMAT_UNKNOWN;
+        d3d11CommandBuffer->colorTargetSubresources[i] = NULL;
+        d3d11CommandBuffer->colorResolveSubresources[i] = NULL;
     }
 
     // Set up the new color target bindings
@@ -3523,16 +3471,20 @@ static void D3D11_BeginRenderPass(
             colorTargetInfos[i].mip_level,
             colorTargetInfos[i].cycle);
 
-        if (subresource->msaaHandle != NULL) {
-            d3d11CommandBuffer->colorTargetResolveTexture[i] = subresource->parent;
-            d3d11CommandBuffer->colorTargetResolveSubresourceIndex[i] = subresource->index;
-            d3d11CommandBuffer->colorTargetMsaaHandle[i] = subresource->msaaHandle;
-            d3d11CommandBuffer->colorTargetMsaaFormat[i] = SDLToD3D11_TextureFormat[container->header.info.format];
+        Uint32 rtvIndex = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0;
+        rtvs[i] = subresource->colorTargetViews[rtvIndex];
+        d3d11CommandBuffer->colorTargetSubresources[i] = subresource;
 
-            rtvs[i] = subresource->msaaTargetView;
-        } else {
-            Uint32 rtvIndex = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0;
-            rtvs[i] = subresource->colorTargetViews[rtvIndex];
+        if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
+            D3D11TextureContainer *resolveContainer = (D3D11TextureContainer *)colorTargetInfos[i].resolve_texture;
+            D3D11TextureSubresource *resolveSubresource = D3D11_INTERNAL_PrepareTextureSubresourceForWrite(
+                renderer,
+                resolveContainer,
+                colorTargetInfos[i].resolve_layer,
+                colorTargetInfos[i].resolve_mip_level,
+                colorTargetInfos[i].cycle_resolve_texture);
+
+            d3d11CommandBuffer->colorResolveSubresources[i] = resolveSubresource;
         }
 
         if (colorTargetInfos[i].load_op == SDL_GPU_LOADOP_CLEAR) {
@@ -4220,14 +4172,14 @@ static void D3D11_EndRenderPass(
 
     // Resolve MSAA color render targets
     for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) {
-        if (d3d11CommandBuffer->colorTargetMsaaHandle[i] != NULL) {
+        if (d3d11CommandBuffer->colorResolveSubresources[i] != NULL) {
             ID3D11DeviceContext_ResolveSubresource(
                 d3d11CommandBuffer->context,
-                d3d11CommandBuffer->colorTargetResolveTexture[i]->handle,
-                d3d11CommandBuffer->colorTargetResolveSubresourceIndex[i],
-                d3d11CommandBuffer->colorTargetMsaaHandle[i],
-                0,
-                d3d11CommandBuffer->colorTargetMsaaFormat[i]);
+                d3d11CommandBuffer->colorResolveSubresources[i]->parent->handle,
+                d3d11CommandBuffer->colorResolveSubresources[i]->index,
+                d3d11CommandBuffer->colorTargetSubresources[i]->parent->handle,
+                d3d11CommandBuffer->colorTargetSubresources[i]->index,
+                SDLToD3D11_TextureFormat[d3d11CommandBuffer->colorTargetSubresources[i]->parent->container->header.info.format]);
         }
     }
 
@@ -5083,8 +5035,6 @@ static bool D3D11_INTERNAL_InitializeSwapchainTexture(
         return false;
     }
 
-    // Create container
-
     // Fill out the texture struct
     pTexture->handle = NULL;     // This will be set in AcquireSwapchainTexture.
     pTexture->shaderView = NULL; // We don't allow swapchain texture to be sampled
@@ -5095,8 +5045,6 @@ static bool D3D11_INTERNAL_InitializeSwapchainTexture(
     pTexture->subresources[0].colorTargetViews[0] = rtv;
     pTexture->subresources[0].uav = NULL;
     pTexture->subresources[0].depthStencilTargetView = NULL;
-    pTexture->subresources[0].msaaHandle = NULL;
-    pTexture->subresources[0].msaaTargetView = NULL;
     pTexture->subresources[0].layer = 0;
     pTexture->subresources[0].level = 0;
     pTexture->subresources[0].depth = 1;

+ 92 - 48
src/gpu/d3d12/SDL_gpu_d3d12.c

@@ -673,8 +673,8 @@ struct D3D12CommandBuffer
     Uint32 presentDataCount;
     Uint32 presentDataCapacity;
 
-    Uint32 colorTargetTextureSubresourceCount;
-    D3D12TextureSubresource *colorTargetTextureSubresources[MAX_COLOR_TARGET_BINDINGS];
+    D3D12TextureSubresource *colorTargetSubresources[MAX_COLOR_TARGET_BINDINGS];
+    D3D12TextureSubresource *colorResolveSubresources[MAX_COLOR_TARGET_BINDINGS];
     D3D12TextureSubresource *depthStencilTextureSubresource;
     D3D12GraphicsPipeline *currentGraphicsPipeline;
     D3D12ComputePipeline *currentComputePipeline;
@@ -2619,7 +2619,7 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
 
     psoDesc.SampleMask = sampleMask;
     psoDesc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->multisample_state.sample_count];
-    psoDesc.SampleDesc.Quality = 0;
+    psoDesc.SampleDesc.Quality = (createinfo->multisample_state.sample_count > SDL_GPU_SAMPLECOUNT_1) ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0;
 
     psoDesc.DSVFormat = SDLToD3D12_TextureFormat[createinfo->target_info.depth_stencil_format];
     psoDesc.NumRenderTargets = createinfo->target_info.num_color_targets;
@@ -2787,6 +2787,7 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture(
 
     Uint32 layerCount = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? 1 : createinfo->layer_count_or_depth;
     Uint32 depth = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? createinfo->layer_count_or_depth : 1;
+    bool isMultisample = createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1;
 
     if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
         resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
@@ -2824,8 +2825,8 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture(
         desc.DepthOrArraySize = (UINT16)createinfo->layer_count_or_depth;
         desc.MipLevels = (UINT16)createinfo->num_levels;
         desc.Format = SDLToD3D12_TextureFormat[createinfo->format];
-        desc.SampleDesc.Count = 1;
-        desc.SampleDesc.Quality = 0;
+        desc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->sample_count];
+        desc.SampleDesc.Quality = isMultisample ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0;
         desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // Apparently this is the most efficient choice
         desc.Flags = resourceFlags;
     } else {
@@ -2956,21 +2957,31 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture(
 
                     rtvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format];
 
-                    if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
-                        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
-                        rtvDesc.Texture2DArray.MipSlice = levelIndex;
-                        rtvDesc.Texture2DArray.FirstArraySlice = layerIndex;
-                        rtvDesc.Texture2DArray.ArraySize = 1;
-                        rtvDesc.Texture2DArray.PlaneSlice = 0;
-                    } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
-                        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
-                        rtvDesc.Texture3D.MipSlice = levelIndex;
-                        rtvDesc.Texture3D.FirstWSlice = depthIndex;
-                        rtvDesc.Texture3D.WSize = 1;
+                    if (isMultisample) {
+                        if (createinfo->type == SDL_GPU_TEXTURETYPE_2D) {
+                            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
+                        } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
+                            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
+                            rtvDesc.Texture2DMSArray.FirstArraySlice = layerIndex;
+                            rtvDesc.Texture2DMSArray.ArraySize = 1;
+                        }
                     } else {
-                        rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
-                        rtvDesc.Texture2D.MipSlice = levelIndex;
-                        rtvDesc.Texture2D.PlaneSlice = 0;
+                        if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
+                            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
+                            rtvDesc.Texture2DArray.MipSlice = levelIndex;
+                            rtvDesc.Texture2DArray.FirstArraySlice = layerIndex;
+                            rtvDesc.Texture2DArray.ArraySize = 1;
+                            rtvDesc.Texture2DArray.PlaneSlice = 0;
+                        } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
+                            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
+                            rtvDesc.Texture3D.MipSlice = levelIndex;
+                            rtvDesc.Texture3D.FirstWSlice = depthIndex;
+                            rtvDesc.Texture3D.WSize = 1;
+                        } else {
+                            rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+                            rtvDesc.Texture2D.MipSlice = levelIndex;
+                            rtvDesc.Texture2D.PlaneSlice = 0;
+                        }
                     }
 
                     ID3D12Device_CreateRenderTargetView(
@@ -2992,8 +3003,13 @@ static D3D12Texture *D3D12_INTERNAL_CreateTexture(
 
                 dsvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format];
                 dsvDesc.Flags = (D3D12_DSV_FLAGS)0;
-                dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
-                dsvDesc.Texture2D.MipSlice = levelIndex;
+
+                if (isMultisample) {
+                    dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
+                } else {
+                    dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
+                    dsvDesc.Texture2D.MipSlice = levelIndex;
+                }
 
                 ID3D12Device_CreateDepthStencilView(
                     renderer->device,
@@ -3886,11 +3902,6 @@ static void D3D12_BeginRenderPass(
         if (h < framebufferHeight) {
             framebufferHeight = h;
         }
-
-        if (!(container->header.info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Color target texture was not designated as a color target!");
-            return;
-        }
     }
 
     if (depthStencilTargetInfo != NULL) {
@@ -3908,12 +3919,6 @@ static void D3D12_BeginRenderPass(
         if (h < framebufferHeight) {
             framebufferHeight = h;
         }
-
-        // Fixme:
-        if (!(container->header.info.usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET)) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Depth stencil target texture was not designated as a depth target!");
-            return;
-        }
     }
 
     D3D12_CPU_DESCRIPTOR_HANDLE rtvs[MAX_COLOR_TARGET_BINDINGS];
@@ -3929,8 +3934,7 @@ static void D3D12_BeginRenderPass(
             D3D12_RESOURCE_STATE_RENDER_TARGET);
 
         Uint32 rtvIndex = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0;
-        D3D12_CPU_DESCRIPTOR_HANDLE rtv =
-            subresource->rtvHandles[rtvIndex].cpuHandle;
+        D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->rtvHandles[rtvIndex].cpuHandle;
 
         if (colorTargetInfos[i].load_op == SDL_GPU_LOADOP_CLEAR) {
             float clearColor[4];
@@ -3948,12 +3952,24 @@ static void D3D12_BeginRenderPass(
         }
 
         rtvs[i] = rtv;
-        d3d12CommandBuffer->colorTargetTextureSubresources[i] = subresource;
+        d3d12CommandBuffer->colorTargetSubresources[i] = subresource;
 
         D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, subresource->parent);
-    }
 
-    d3d12CommandBuffer->colorTargetTextureSubresourceCount = numColorTargets;
+        if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
+            D3D12TextureContainer *resolveContainer = (D3D12TextureContainer *)colorTargetInfos[i].resolve_texture;
+            D3D12TextureSubresource *resolveSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
+                d3d12CommandBuffer,
+                resolveContainer,
+                colorTargetInfos[i].resolve_layer,
+                colorTargetInfos[i].resolve_mip_level,
+                colorTargetInfos[i].cycle_resolve_texture,
+                D3D12_RESOURCE_STATE_RESOLVE_DEST);
+
+            d3d12CommandBuffer->colorResolveSubresources[i] = resolveSubresource;
+            D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, resolveSubresource->parent);
+        }
+    }
 
     D3D12_CPU_DESCRIPTOR_HANDLE dsv;
     if (depthStencilTargetInfo != NULL) {
@@ -4780,15 +4796,42 @@ static void D3D12_EndRenderPass(
     D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
     Uint32 i;
 
-    for (i = 0; i < d3d12CommandBuffer->colorTargetTextureSubresourceCount; i += 1) {
-        D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
-            d3d12CommandBuffer,
-            D3D12_RESOURCE_STATE_RENDER_TARGET,
-            d3d12CommandBuffer->colorTargetTextureSubresources[i]);
-
-        d3d12CommandBuffer->colorTargetTextureSubresources[i] = NULL;
+    for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) {
+        if (d3d12CommandBuffer->colorTargetSubresources[i] != NULL) {
+            if (d3d12CommandBuffer->colorResolveSubresources[i] != NULL) {
+                // Resolving requires some extra barriers
+                D3D12_INTERNAL_TextureSubresourceBarrier(
+                    d3d12CommandBuffer,
+                    D3D12_RESOURCE_STATE_RENDER_TARGET,
+                    D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
+                    d3d12CommandBuffer->colorTargetSubresources[i]
+                );
+
+                ID3D12GraphicsCommandList_ResolveSubresource(
+                    d3d12CommandBuffer->graphicsCommandList,
+                    d3d12CommandBuffer->colorResolveSubresources[i]->parent->resource,
+                    d3d12CommandBuffer->colorResolveSubresources[i]->index,
+                    d3d12CommandBuffer->colorTargetSubresources[i]->parent->resource,
+                    d3d12CommandBuffer->colorTargetSubresources[i]->index,
+                    SDLToD3D12_TextureFormat[d3d12CommandBuffer->colorTargetSubresources[i]->parent->container->header.info.format]);
+
+                D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
+                    d3d12CommandBuffer,
+                    D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
+                    d3d12CommandBuffer->colorTargetSubresources[i]);
+
+                D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
+                    d3d12CommandBuffer,
+                    D3D12_RESOURCE_STATE_RESOLVE_DEST,
+                    d3d12CommandBuffer->colorResolveSubresources[i]);
+            } else {
+                D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
+                    d3d12CommandBuffer,
+                    D3D12_RESOURCE_STATE_RENDER_TARGET,
+                    d3d12CommandBuffer->colorTargetSubresources[i]);
+            }
+        }
     }
-    d3d12CommandBuffer->colorTargetTextureSubresourceCount = 0;
 
     if (d3d12CommandBuffer->depthStencilTextureSubresource != NULL) {
         D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
@@ -4809,7 +4852,8 @@ static void D3D12_EndRenderPass(
         NULL);
 
     // Reset bind state
-    SDL_zeroa(d3d12CommandBuffer->colorTargetTextureSubresources);
+    SDL_zeroa(d3d12CommandBuffer->colorTargetSubresources);
+    SDL_zeroa(d3d12CommandBuffer->colorResolveSubresources);
     d3d12CommandBuffer->depthStencilTextureSubresource = NULL;
 
     SDL_zeroa(d3d12CommandBuffer->vertexBuffers);
@@ -6820,8 +6864,8 @@ static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer(
     // Set the bind state
     commandBuffer->currentGraphicsPipeline = NULL;
 
-    SDL_zeroa(commandBuffer->colorTargetTextureSubresources);
-    commandBuffer->colorTargetTextureSubresourceCount = 0;
+    SDL_zeroa(commandBuffer->colorTargetSubresources);
+    SDL_zeroa(commandBuffer->colorResolveSubresources);
     commandBuffer->depthStencilTextureSubresource = NULL;
 
     SDL_zeroa(commandBuffer->vertexBuffers);

+ 29 - 65
src/gpu/metal/SDL_gpu_metal.m

@@ -294,6 +294,13 @@ static MTLLoadAction SDLToMetal_LoadOp[] = {
     MTLLoadActionDontCare, // DONT_CARE
 };
 
+static MTLStoreAction SDLToMetal_StoreOp[] = {
+    MTLStoreActionStore,
+    MTLStoreActionDontCare,
+    MTLStoreActionMultisampleResolve,
+    MTLStoreActionStoreAndMultisampleResolve
+};
+
 static MTLVertexStepFunction SDLToMetal_StepFunction[] = {
     MTLVertexStepFunctionPerVertex,
     MTLVertexStepFunctionPerInstance,
@@ -323,25 +330,6 @@ static SDL_GPUTextureFormat SwapchainCompositionToFormat[] = {
 
 static CFStringRef SwapchainCompositionToColorSpace[4]; // initialized on device creation
 
-static MTLStoreAction SDLToMetal_StoreOp(
-    SDL_GPUStoreOp storeOp,
-    Uint8 isMultisample)
-{
-    if (isMultisample) {
-        if (storeOp == SDL_GPU_STOREOP_STORE) {
-            return MTLStoreActionStoreAndMultisampleResolve;
-        } else {
-            return MTLStoreActionMultisampleResolve;
-        }
-    } else {
-        if (storeOp == SDL_GPU_STOREOP_STORE) {
-            return MTLStoreActionStore;
-        } else {
-            return MTLStoreActionDontCare;
-        }
-    }
-};
-
 static MTLColorWriteMask SDLToMetal_ColorWriteMask(
     SDL_GPUColorComponentFlags mask)
 {
@@ -366,7 +354,6 @@ static MTLColorWriteMask SDLToMetal_ColorWriteMask(
 typedef struct MetalTexture
 {
     id<MTLTexture> handle;
-    id<MTLTexture> msaaHandle;
     SDL_AtomicInt referenceCount;
 } MetalTexture;
 
@@ -828,7 +815,6 @@ static void METAL_INTERNAL_DestroyTextureContainer(
 {
     for (Uint32 i = 0; i < container->textureCount; i += 1) {
         container->textures[i]->handle = nil;
-        container->textures[i]->msaaHandle = nil;
         SDL_free(container->textures[i]);
     }
     if (container->debugName != NULL) {
@@ -1329,7 +1315,6 @@ static MetalTexture *METAL_INTERNAL_CreateTexture(
 {
     MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor new];
     id<MTLTexture> texture;
-    id<MTLTexture> msaaTexture = NULL;
     MetalTexture *metalTexture;
 
     textureDescriptor.textureType = SDLToMetal_TextureType[createinfo->type];
@@ -1347,7 +1332,7 @@ static MetalTexture *METAL_INTERNAL_CreateTexture(
     textureDescriptor.height = createinfo->height;
     textureDescriptor.depth = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? createinfo->layer_count_or_depth : 1;
     textureDescriptor.mipmapLevelCount = createinfo->num_levels;
-    textureDescriptor.sampleCount = 1;
+    textureDescriptor.sampleCount = SDLToMetal_SampleCount[createinfo->sample_count];
     textureDescriptor.arrayLength =
         (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY)
             ? createinfo->layer_count_or_depth
@@ -1374,22 +1359,8 @@ static MetalTexture *METAL_INTERNAL_CreateTexture(
         return NULL;
     }
 
-    // Create the MSAA texture, if needed
-    if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->type == SDL_GPU_TEXTURETYPE_2D) {
-        textureDescriptor.textureType = MTLTextureType2DMultisample;
-        textureDescriptor.sampleCount = SDLToMetal_SampleCount[createinfo->sample_count];
-        textureDescriptor.usage = MTLTextureUsageRenderTarget;
-
-        msaaTexture = [renderer->device newTextureWithDescriptor:textureDescriptor];
-        if (msaaTexture == NULL) {
-            SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create MSAA MTLTexture!");
-            return NULL;
-        }
-    }
-
     metalTexture = (MetalTexture *)SDL_calloc(1, sizeof(MetalTexture));
     metalTexture->handle = texture;
-    metalTexture->msaaHandle = msaaTexture;
     SDL_AtomicSet(&metalTexture->referenceCount, 0);
     return metalTexture;
 }
@@ -2189,12 +2160,7 @@ static void METAL_BeginRenderPass(
                 container,
                 colorTargetInfos[i].cycle);
 
-            if (texture->msaaHandle) {
-                passDescriptor.colorAttachments[i].texture = texture->msaaHandle;
-                passDescriptor.colorAttachments[i].resolveTexture = texture->handle;
-            } else {
-                passDescriptor.colorAttachments[i].texture = texture->handle;
-            }
+            passDescriptor.colorAttachments[i].texture = texture->handle;
             passDescriptor.colorAttachments[i].level = colorTargetInfos[i].mip_level;
             if (container->header.info.type == SDL_GPU_TEXTURETYPE_3D) {
                 passDescriptor.colorAttachments[i].depthPlane = colorTargetInfos[i].layer_or_depth_plane;
@@ -2207,11 +2173,23 @@ static void METAL_BeginRenderPass(
                 colorTargetInfos[i].clear_color.b,
                 colorTargetInfos[i].clear_color.a);
             passDescriptor.colorAttachments[i].loadAction = SDLToMetal_LoadOp[colorTargetInfos[i].load_op];
-            passDescriptor.colorAttachments[i].storeAction = SDLToMetal_StoreOp(
-                colorTargetInfos[i].store_op,
-                texture->msaaHandle ? 1 : 0);
+            passDescriptor.colorAttachments[i].storeAction = SDLToMetal_StoreOp[colorTargetInfos[i].store_op];
 
             METAL_INTERNAL_TrackTexture(metalCommandBuffer, texture);
+
+            if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
+                MetalTextureContainer *resolveContainer = (MetalTextureContainer *)colorTargetInfos[i].resolve_texture;
+                MetalTexture *resolveTexture = METAL_INTERNAL_PrepareTextureForWrite(
+                    renderer,
+                    resolveContainer,
+                    colorTargetInfos[i].cycle_resolve_texture);
+
+                passDescriptor.colorAttachments[i].resolveTexture = resolveTexture->handle;
+                passDescriptor.colorAttachments[i].resolveSlice = colorTargetInfos[i].resolve_layer;
+                passDescriptor.colorAttachments[i].resolveLevel = colorTargetInfos[i].resolve_mip_level;
+
+                METAL_INTERNAL_TrackTexture(metalCommandBuffer, resolveTexture);
+            }
         }
 
         if (depthStencilTargetInfo != NULL) {
@@ -2221,29 +2199,15 @@ static void METAL_BeginRenderPass(
                 container,
                 depthStencilTargetInfo->cycle);
 
-            if (texture->msaaHandle) {
-                passDescriptor.depthAttachment.texture = texture->msaaHandle;
-                passDescriptor.depthAttachment.resolveTexture = texture->handle;
-            } else {
-                passDescriptor.depthAttachment.texture = texture->handle;
-            }
+            passDescriptor.depthAttachment.texture = texture->handle;
             passDescriptor.depthAttachment.loadAction = SDLToMetal_LoadOp[depthStencilTargetInfo->load_op];
-            passDescriptor.depthAttachment.storeAction = SDLToMetal_StoreOp(
-                depthStencilTargetInfo->store_op,
-                texture->msaaHandle ? 1 : 0);
+            passDescriptor.depthAttachment.storeAction = SDLToMetal_StoreOp[depthStencilTargetInfo->store_op];
             passDescriptor.depthAttachment.clearDepth = depthStencilTargetInfo->clear_depth;
 
             if (IsStencilFormat(container->header.info.format)) {
-                if (texture->msaaHandle) {
-                    passDescriptor.stencilAttachment.texture = texture->msaaHandle;
-                    passDescriptor.stencilAttachment.resolveTexture = texture->handle;
-                } else {
-                    passDescriptor.stencilAttachment.texture = texture->handle;
-                }
-                passDescriptor.stencilAttachment.loadAction = SDLToMetal_LoadOp[depthStencilTargetInfo->load_op];
-                passDescriptor.stencilAttachment.storeAction = SDLToMetal_StoreOp(
-                    depthStencilTargetInfo->store_op,
-                    texture->msaaHandle ? 1 : 0);
+                passDescriptor.stencilAttachment.texture = texture->handle;
+                passDescriptor.stencilAttachment.loadAction = SDLToMetal_LoadOp[depthStencilTargetInfo->stencil_load_op];
+                passDescriptor.stencilAttachment.storeAction = SDLToMetal_StoreOp[depthStencilTargetInfo->stencil_store_op];
                 passDescriptor.stencilAttachment.clearStencil = depthStencilTargetInfo->clear_stencil;
             }
 

File diff suppressed because it is too large
+ 156 - 378
src/gpu/vulkan/SDL_gpu_vulkan.c


+ 71 - 30
test/testgpu_spinning_cube.c

@@ -42,7 +42,7 @@ typedef struct RenderState
 typedef struct WindowState
 {
     int angle_x, angle_y, angle_z;
-    SDL_GPUTexture *tex_depth, *tex_msaa;
+    SDL_GPUTexture *tex_depth, *tex_msaa, *tex_resolve;
     Uint32 prev_drawablew, prev_drawableh;
 } WindowState;
 
@@ -59,6 +59,7 @@ static void shutdownGPU(void)
             WindowState *winstate = &window_states[i];
             SDL_ReleaseGPUTexture(gpu_device, winstate->tex_depth);
             SDL_ReleaseGPUTexture(gpu_device, winstate->tex_msaa);
+            SDL_ReleaseGPUTexture(gpu_device, winstate->tex_resolve);
             SDL_ReleaseWindowFromGPUDevice(gpu_device, state->windows[i]);
         }
         SDL_free(window_states);
@@ -249,20 +250,20 @@ static const VertexData vertex_data[] = {
 static SDL_GPUTexture*
 CreateDepthTexture(Uint32 drawablew, Uint32 drawableh)
 {
-    SDL_GPUTextureCreateInfo depthtex_createinfo;
+    SDL_GPUTextureCreateInfo createinfo;
     SDL_GPUTexture *result;
 
-    depthtex_createinfo.type = SDL_GPU_TEXTURETYPE_2D;
-    depthtex_createinfo.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
-    depthtex_createinfo.width = drawablew;
-    depthtex_createinfo.height = drawableh;
-    depthtex_createinfo.layer_count_or_depth = 1;
-    depthtex_createinfo.num_levels = 1;
-    depthtex_createinfo.sample_count = render_state.sample_count;
-    depthtex_createinfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET;
-    depthtex_createinfo.props = 0;
-
-    result = SDL_CreateGPUTexture(gpu_device, &depthtex_createinfo);
+    createinfo.type = SDL_GPU_TEXTURETYPE_2D;
+    createinfo.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
+    createinfo.width = drawablew;
+    createinfo.height = drawableh;
+    createinfo.layer_count_or_depth = 1;
+    createinfo.num_levels = 1;
+    createinfo.sample_count = render_state.sample_count;
+    createinfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET;
+    createinfo.props = 0;
+
+    result = SDL_CreateGPUTexture(gpu_device, &createinfo);
     CHECK_CREATE(result, "Depth Texture")
 
     return result;
@@ -271,29 +272,55 @@ CreateDepthTexture(Uint32 drawablew, Uint32 drawableh)
 static SDL_GPUTexture*
 CreateMSAATexture(Uint32 drawablew, Uint32 drawableh)
 {
-    SDL_GPUTextureCreateInfo msaatex_createinfo;
+    SDL_GPUTextureCreateInfo createinfo;
     SDL_GPUTexture *result;
 
     if (render_state.sample_count == SDL_GPU_SAMPLECOUNT_1) {
         return NULL;
     }
 
-    msaatex_createinfo.type = SDL_GPU_TEXTURETYPE_2D;
-    msaatex_createinfo.format = SDL_GetGPUSwapchainTextureFormat(gpu_device, state->windows[0]);
-    msaatex_createinfo.width = drawablew;
-    msaatex_createinfo.height = drawableh;
-    msaatex_createinfo.layer_count_or_depth = 1;
-    msaatex_createinfo.num_levels = 1;
-    msaatex_createinfo.sample_count = render_state.sample_count;
-    msaatex_createinfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER;
-    msaatex_createinfo.props = 0;
-
-    result = SDL_CreateGPUTexture(gpu_device, &msaatex_createinfo);
+    createinfo.type = SDL_GPU_TEXTURETYPE_2D;
+    createinfo.format = SDL_GetGPUSwapchainTextureFormat(gpu_device, state->windows[0]);
+    createinfo.width = drawablew;
+    createinfo.height = drawableh;
+    createinfo.layer_count_or_depth = 1;
+    createinfo.num_levels = 1;
+    createinfo.sample_count = render_state.sample_count;
+    createinfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
+    createinfo.props = 0;
+
+    result = SDL_CreateGPUTexture(gpu_device, &createinfo);
     CHECK_CREATE(result, "MSAA Texture")
 
     return result;
 }
 
+static SDL_GPUTexture *
+CreateResolveTexture(Uint32 drawablew, Uint32 drawableh)
+{
+    SDL_GPUTextureCreateInfo createinfo;
+    SDL_GPUTexture *result;
+
+    if (render_state.sample_count == SDL_GPU_SAMPLECOUNT_1) {
+        return NULL;
+    }
+
+    createinfo.type = SDL_GPU_TEXTURETYPE_2D;
+    createinfo.format = SDL_GetGPUSwapchainTextureFormat(gpu_device, state->windows[0]);
+    createinfo.width = drawablew;
+    createinfo.height = drawableh;
+    createinfo.layer_count_or_depth = 1;
+    createinfo.num_levels = 1;
+    createinfo.sample_count = SDL_GPU_SAMPLECOUNT_1;
+    createinfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER;
+    createinfo.props = 0;
+
+    result = SDL_CreateGPUTexture(gpu_device, &createinfo);
+    CHECK_CREATE(result, "Resolve Texture")
+
+    return result;
+}
+
 static void
 Render(SDL_Window *window, const int windownum)
 {
@@ -354,8 +381,10 @@ Render(SDL_Window *window, const int windownum)
     if (winstate->prev_drawablew != drawablew || winstate->prev_drawableh != drawableh) {
         SDL_ReleaseGPUTexture(gpu_device, winstate->tex_depth);
         SDL_ReleaseGPUTexture(gpu_device, winstate->tex_msaa);
+        SDL_ReleaseGPUTexture(gpu_device, winstate->tex_resolve);
         winstate->tex_depth = CreateDepthTexture(drawablew, drawableh);
         winstate->tex_msaa = CreateMSAATexture(drawablew, drawableh);
+        winstate->tex_resolve = CreateResolveTexture(drawablew, drawableh);
     }
     winstate->prev_drawablew = drawablew;
     winstate->prev_drawableh = drawableh;
@@ -364,14 +393,25 @@ Render(SDL_Window *window, const int windownum)
 
     SDL_zero(color_target);
     color_target.clear_color.a = 1.0f;
-    color_target.load_op = SDL_GPU_LOADOP_CLEAR;
-    color_target.store_op = SDL_GPU_STOREOP_STORE;
-    color_target.texture = winstate->tex_msaa ? winstate->tex_msaa : swapchain;
+    if (winstate->tex_msaa) {
+        color_target.load_op = SDL_GPU_LOADOP_CLEAR;
+        color_target.store_op = SDL_GPU_STOREOP_RESOLVE;
+        color_target.texture = winstate->tex_msaa;
+        color_target.resolve_texture = winstate->tex_resolve;
+        color_target.cycle = SDL_TRUE;
+        color_target.cycle_resolve_texture = SDL_TRUE;
+    } else {
+        color_target.load_op = SDL_GPU_LOADOP_CLEAR;
+        color_target.store_op = SDL_GPU_STOREOP_STORE;
+        color_target.texture = swapchain;
+    }
 
     SDL_zero(depth_target);
     depth_target.clear_depth = 1.0f;
     depth_target.load_op = SDL_GPU_LOADOP_CLEAR;
     depth_target.store_op = SDL_GPU_STOREOP_DONT_CARE;
+    depth_target.stencil_load_op = SDL_GPU_LOADOP_DONT_CARE;
+    depth_target.stencil_store_op = SDL_GPU_STOREOP_DONT_CARE;
     depth_target.texture = winstate->tex_depth;
     depth_target.cycle = SDL_TRUE;
 
@@ -390,10 +430,10 @@ Render(SDL_Window *window, const int windownum)
     SDL_DrawGPUPrimitives(pass, 36, 1, 0, 0);
     SDL_EndGPURenderPass(pass);
 
-    /* Blit MSAA to swapchain, if needed */
+    /* Blit MSAA resolve target to swapchain, if needed */
     if (render_state.sample_count > SDL_GPU_SAMPLECOUNT_1) {
         SDL_zero(blit_info);
-        blit_info.source.texture = winstate->tex_msaa;
+        blit_info.source.texture = winstate->tex_resolve;
         blit_info.source.w = drawablew;
         blit_info.source.h = drawableh;
 
@@ -609,6 +649,7 @@ init_render_state(int msaa)
         SDL_GetWindowSizeInPixels(state->windows[i], (int*) &drawablew, (int*) &drawableh);
         winstate->tex_depth = CreateDepthTexture(drawablew, drawableh);
         winstate->tex_msaa = CreateMSAATexture(drawablew, drawableh);
+        winstate->tex_resolve = CreateResolveTexture(drawablew, drawableh);
 
         /* make each window different */
         winstate->angle_x = (i * 10) % 360;

Some files were not shown because too many files changed in this diff