From 9416917353cf54fc6753f7f5e557f55214ed86f6 Mon Sep 17 00:00:00 2001
From: Caleb Cornett <[EMAIL REDACTED]>
Date: Mon, 16 Sep 2024 12:19:09 -0500
Subject: [PATCH] GPU: Rework MSAA (#10859)
---
include/SDL3/SDL_gpu.h | 39 +-
src/gpu/SDL_gpu.c | 66 +-
src/gpu/d3d11/SDL_gpu_d3d11.c | 158 ++--
src/gpu/d3d12/SDL_gpu_d3d12.c | 140 ++--
src/gpu/metal/SDL_gpu_metal.m | 94 +--
src/gpu/vulkan/SDL_gpu_vulkan.c | 1291 +++++++++++--------------------
test/testgpu_spinning_cube.c | 101 ++-
7 files changed, 777 insertions(+), 1112 deletions(-)
diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index 6ad4532ba1e80..c411eacc07634 100644
--- a/include/SDL3/SDL_gpu.h
+++ b/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
diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c
index b458894b71b6a..29698506e590e 100644
--- a/src/gpu/SDL_gpu.c
+++ b/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;
diff --git a/src/gpu/d3d11/SDL_gpu_d3d11.c b/src/gpu/d3d11/SDL_gpu_d3d11.c
index ef18ce6aebc1c..b78c00c54eb52 100644
--- a/src/gpu/d3d11/SDL_gpu_d3d11.c
+++ b/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;
diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c
index f3c9e18e9920f..06e60744fda18 100644
--- a/src/gpu/d3d12/SDL_gpu_d3d12.c
+++ b/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 = D3D1
(Patch may be truncated, please check the link at the top of this post.)