diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index ac4e0e67b28f37..711b8c0b133312 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -272,6 +272,13 @@ static void METAL_UnclaimWindow( MTLVertexStepFunctionPerInstance, }; +static NSUInteger SDLToMetal_SampleCount[] = { + 1, /* SDL_GPU_SAMPLECOUNT_1 */ + 2, /* SDL_GPU_SAMPLECOUNT_2 */ + 4, /* SDL_GPU_SAMPLECOUNT_4 */ + 8 /* SDL_GPU_SAMPLECOUNT_8 */ +}; + static SDL_GpuTextureFormat SwapchainCompositionToFormat[] = { SDL_GPU_TEXTUREFORMAT_B8G8R8A8, /* SDR */ SDL_GPU_TEXTUREFORMAT_B8G8R8A8_SRGB, /* SDR_LINEAR */ @@ -324,6 +331,7 @@ static MTLColorWriteMask SDLToMetal_ColorWriteMask( typedef struct MetalTexture { id handle; + id msaaHandle; SDL_AtomicInt referenceCount; } MetalTexture; @@ -719,16 +727,14 @@ static MetalLibraryFunction METAL_INTERNAL_CompileShader( if (format == SDL_GPU_SHADERFORMAT_MSL) { library = [renderer->device newLibraryWithSource:@((const char *)code) - options:nil /* FIXME: Do we need any compile options? */ + options:nil error:&error]; } else if (format == SDL_GPU_SHADERFORMAT_METALLIB) { data = dispatch_data_create( code, codeSize, dispatch_get_global_queue(0, 0), - ^{ - } /* FIXME: is this right? */ - ); + ^{ /* do nothing */ }); library = [renderer->device newLibraryWithData:data error:&error]; } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Incompatible shader format for Metal"); @@ -962,7 +968,9 @@ static void METAL_ReleaseGraphicsPipeline( pipelineDescriptor.colorAttachments[i].destinationAlphaBlendFactor = SDLToMetal_BlendFactor[blendState->dstAlphaBlendFactor]; } - /* FIXME: Multisample */ + /* Multisample */ + + pipelineDescriptor.rasterSampleCount = SDLToMetal_SampleCount[pipelineCreateInfo->multisampleState.multisampleCount]; /* Depth Stencil */ @@ -1248,27 +1256,22 @@ static void METAL_PopDebugGroup( { MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor new]; id texture; + id msaaTexture = NULL; MetalTexture *metalTexture; - /* FIXME: MSAA? */ - if (textureCreateInfo->depth > 1) { - textureDescriptor.textureType = MTLTextureType3D; - } else if (textureCreateInfo->isCube) { - textureDescriptor.textureType = MTLTextureTypeCube; + if (textureCreateInfo->depth <= 1) { + if (textureCreateInfo->isCube) { + textureDescriptor.textureType = MTLTextureTypeCube; + } else if (textureCreateInfo->layerCount > 1) { + textureDescriptor.textureType = MTLTextureType2DArray; + } else { + textureDescriptor.textureType = MTLTextureType2D; + } } else { - textureDescriptor.textureType = MTLTextureType2D; + textureDescriptor.textureType = MTLTextureType3D; } textureDescriptor.pixelFormat = SDLToMetal_SurfaceFormat[textureCreateInfo->format]; - textureDescriptor.width = textureCreateInfo->width; - textureDescriptor.height = textureCreateInfo->height; - textureDescriptor.depth = textureCreateInfo->depth; - textureDescriptor.mipmapLevelCount = textureCreateInfo->levelCount; - textureDescriptor.sampleCount = 1; /* FIXME */ - textureDescriptor.arrayLength = 1; /* FIXME: Is this used outside of cubes? */ - textureDescriptor.resourceOptions = MTLResourceCPUCacheModeDefaultCache | MTLResourceStorageModePrivate | MTLResourceHazardTrackingModeDefault; - textureDescriptor.allowGPUOptimizedContents = true; - /* This format isn't natively supported so let's swizzle! */ if (textureCreateInfo->format == SDL_GPU_TEXTUREFORMAT_B4G4R4A4) { textureDescriptor.swizzle = MTLTextureSwizzleChannelsMake( @@ -1278,17 +1281,27 @@ static void METAL_PopDebugGroup( MTLTextureSwizzleAlpha); } + textureDescriptor.width = textureCreateInfo->width; + textureDescriptor.height = textureCreateInfo->height; + textureDescriptor.depth = textureCreateInfo->depth; + textureDescriptor.mipmapLevelCount = textureCreateInfo->levelCount; + textureDescriptor.sampleCount = 1; + textureDescriptor.arrayLength = (textureCreateInfo->isCube) ? 1 : textureCreateInfo->layerCount; /* FIXME: Cube arrays? */ + textureDescriptor.storageMode = MTLStorageModePrivate; + textureDescriptor.usage = 0; - if (textureCreateInfo->usageFlags & (SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT | SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT)) { + if (textureCreateInfo->usageFlags & (SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT | + SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT)) { textureDescriptor.usage |= MTLTextureUsageRenderTarget; } - if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT) { + if (textureCreateInfo->usageFlags & (SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT | + SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ_BIT | + SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ_BIT)) { textureDescriptor.usage |= MTLTextureUsageShaderRead; } if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT) { - textureDescriptor.usage |= MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite; + textureDescriptor.usage |= MTLTextureUsageShaderWrite; } - /* FIXME: Other usages! */ texture = [renderer->device newTextureWithDescriptor:textureDescriptor]; if (texture == NULL) { @@ -1296,8 +1309,23 @@ static void METAL_PopDebugGroup( return NULL; } + /* Create the MSAA texture, if needed */ + if (textureCreateInfo->sampleCount > SDL_GPU_SAMPLECOUNT_1 && textureDescriptor.textureType == MTLTextureType2D) { + textureDescriptor.textureType = MTLTextureType2DMultisample; + textureDescriptor.sampleCount = SDLToMetal_SampleCount[textureCreateInfo->sampleCount]; + textureDescriptor.usage = MTLTextureUsageRenderTarget; + + msaaTexture = [renderer->device newTextureWithDescriptor:textureDescriptor]; + if (msaaTexture == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create MSAA MTLTexture!"); + return NULL; + } + } + metalTexture = (MetalTexture *)SDL_malloc(sizeof(MetalTexture)); metalTexture->handle = texture; + metalTexture->msaaHandle = msaaTexture; + SDL_AtomicSet(&metalTexture->referenceCount, 0); return metalTexture; } @@ -2079,53 +2107,75 @@ static void METAL_BeginRenderPass( SDL_GpuDepthStencilAttachmentInfo *depthStencilAttachmentInfo) { MetalCommandBuffer *metalCommandBuffer = (MetalCommandBuffer *)commandBuffer; + MetalRenderer *renderer = metalCommandBuffer->renderer; MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; - SDL_GpuColorAttachmentInfo *attachmentInfo; - MetalTexture *texture; Uint32 vpWidth = UINT_MAX; Uint32 vpHeight = UINT_MAX; MTLViewport viewport; MTLScissorRect scissorRect; for (Uint32 i = 0; i < colorAttachmentCount; i += 1) { - attachmentInfo = &colorAttachmentInfos[i]; - texture = ((MetalTextureContainer *)attachmentInfo->textureSlice.texture)->activeTexture; + MetalTextureContainer *container = (MetalTextureContainer *)colorAttachmentInfos[i].textureSlice.texture; + MetalTexture *texture = METAL_INTERNAL_PrepareTextureForWrite( + renderer, + container, + colorAttachmentInfos[i].cycle); - /* FIXME: cycle! */ - passDescriptor.colorAttachments[i].texture = texture->handle; - passDescriptor.colorAttachments[i].level = attachmentInfo->textureSlice.mipLevel; - passDescriptor.colorAttachments[i].slice = attachmentInfo->textureSlice.layer; + 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].level = colorAttachmentInfos[i].textureSlice.mipLevel; + passDescriptor.colorAttachments[i].slice = colorAttachmentInfos[i].textureSlice.layer; passDescriptor.colorAttachments[i].clearColor = MTLClearColorMake( - attachmentInfo->clearColor.r, - attachmentInfo->clearColor.g, - attachmentInfo->clearColor.b, - attachmentInfo->clearColor.a); - passDescriptor.colorAttachments[i].loadAction = SDLToMetal_LoadOp[attachmentInfo->loadOp]; - passDescriptor.colorAttachments[i].storeAction = SDLToMetal_StoreOp(attachmentInfo->storeOp, 0); - /* FIXME: Resolve texture! Also affects ^! */ + colorAttachmentInfos[i].clearColor.r, + colorAttachmentInfos[i].clearColor.g, + colorAttachmentInfos[i].clearColor.b, + colorAttachmentInfos[i].clearColor.a); + passDescriptor.colorAttachments[i].loadAction = SDLToMetal_LoadOp[colorAttachmentInfos[i].loadOp]; + passDescriptor.colorAttachments[i].storeAction = SDLToMetal_StoreOp( + colorAttachmentInfos[i].storeOp, + texture->msaaHandle ? 1 : 0); METAL_INTERNAL_TrackTexture(metalCommandBuffer, texture); } if (depthStencilAttachmentInfo != NULL) { MetalTextureContainer *container = (MetalTextureContainer *)depthStencilAttachmentInfo->textureSlice.texture; - texture = container->activeTexture; + MetalTexture *texture = METAL_INTERNAL_PrepareTextureForWrite( + renderer, + container, + depthStencilAttachmentInfo->cycle); - /* FIXME: cycle! */ - passDescriptor.depthAttachment.texture = texture->handle; + if (texture->msaaHandle) { + passDescriptor.depthAttachment.texture = texture->msaaHandle; + passDescriptor.depthAttachment.resolveTexture = texture->handle; + } else { + passDescriptor.depthAttachment.texture = texture->handle; + } passDescriptor.depthAttachment.level = depthStencilAttachmentInfo->textureSlice.mipLevel; passDescriptor.depthAttachment.slice = depthStencilAttachmentInfo->textureSlice.layer; passDescriptor.depthAttachment.loadAction = SDLToMetal_LoadOp[depthStencilAttachmentInfo->loadOp]; - passDescriptor.depthAttachment.storeAction = SDLToMetal_StoreOp(depthStencilAttachmentInfo->storeOp, 0); + passDescriptor.depthAttachment.storeAction = SDLToMetal_StoreOp( + depthStencilAttachmentInfo->storeOp, + texture->msaaHandle ? 1 : 0); passDescriptor.depthAttachment.clearDepth = depthStencilAttachmentInfo->depthStencilClearValue.depth; if (IsStencilFormat(container->createInfo.format)) { - /* FIXME: cycle! */ - passDescriptor.stencilAttachment.texture = texture->handle; + if (texture->msaaHandle) { + passDescriptor.stencilAttachment.texture = texture->msaaHandle; + passDescriptor.stencilAttachment.resolveTexture = texture->handle; + } else { + passDescriptor.stencilAttachment.texture = texture->handle; + } passDescriptor.stencilAttachment.level = depthStencilAttachmentInfo->textureSlice.mipLevel; passDescriptor.stencilAttachment.slice = depthStencilAttachmentInfo->textureSlice.layer; passDescriptor.stencilAttachment.loadAction = SDLToMetal_LoadOp[depthStencilAttachmentInfo->loadOp]; - passDescriptor.stencilAttachment.storeAction = SDLToMetal_StoreOp(depthStencilAttachmentInfo->storeOp, 0); + passDescriptor.stencilAttachment.storeAction = SDLToMetal_StoreOp( + depthStencilAttachmentInfo->storeOp, + texture->msaaHandle ? 1 : 0); passDescriptor.stencilAttachment.clearStencil = depthStencilAttachmentInfo->depthStencilClearValue.stencil; } @@ -2149,7 +2199,19 @@ static void METAL_BeginRenderPass( } } - /* FIXME: check depth/stencil attachment size too */ + if (depthStencilAttachmentInfo != NULL) { + MetalTextureContainer *container = (MetalTextureContainer *)depthStencilAttachmentInfo->textureSlice.texture; + Uint32 w = container->createInfo.width >> depthStencilAttachmentInfo->textureSlice.mipLevel; + Uint32 h = container->createInfo.height >> depthStencilAttachmentInfo->textureSlice.mipLevel; + + if (w < vpWidth) { + vpWidth = w; + } + + if (h < vpHeight) { + vpHeight = h; + } + } /* Set default viewport and scissor state */ viewport.originX = 0; @@ -2949,8 +3011,9 @@ static void METAL_Blit( METAL_BindGraphicsPipeline(commandBuffer, pipeline); textureSamplerBinding.texture = source->textureSlice.texture; - textureSamplerBinding.sampler = - filterMode == SDL_GPU_FILTER_NEAREST ? renderer->blitNearestSampler : renderer->blitLinearSampler; + textureSamplerBinding.sampler = (filterMode == SDL_GPU_FILTER_NEAREST) + ? renderer->blitNearestSampler + : renderer->blitLinearSampler; METAL_BindFragmentSamplers( commandBuffer, @@ -3344,7 +3407,7 @@ static Uint8 METAL_INTERNAL_CreateSwapchain( #endif windowData->layer.pixelFormat = SDLToMetal_SurfaceFormat[SwapchainCompositionToFormat[swapchainComposition]]; #ifndef SDL_PLATFORM_TVOS - windowData->layer.wantsExtendedDynamicRangeContent = (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR); /* FIXME: Metadata? */ + windowData->layer.wantsExtendedDynamicRangeContent = (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR); #endif colorspace = CGColorSpaceCreateWithName(SwapchainCompositionToColorSpace[swapchainComposition]); @@ -3363,8 +3426,7 @@ static Uint8 METAL_INTERNAL_CreateSwapchain( windowData->textureContainer.createInfo.levelCount = 1; windowData->textureContainer.createInfo.depth = 1; windowData->textureContainer.createInfo.isCube = 0; - windowData->textureContainer.createInfo.usageFlags = - SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT | SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT; /* FIXME: Other bits? */ + windowData->textureContainer.createInfo.usageFlags = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT | SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT; drawableSize = windowData->layer.drawableSize; windowData->textureContainer.createInfo.width = (Uint32)drawableSize.width; @@ -3555,7 +3617,7 @@ static SDL_bool METAL_SetSwapchainParameters( #endif windowData->layer.pixelFormat = SDLToMetal_SurfaceFormat[SwapchainCompositionToFormat[swapchainComposition]]; #ifndef SDL_PLATFORM_TVOS - windowData->layer.wantsExtendedDynamicRangeContent = (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR); /* FIXME: Metadata? */ + windowData->layer.wantsExtendedDynamicRangeContent = (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR); #endif colorspace = CGColorSpaceCreateWithName(SwapchainCompositionToColorSpace[swapchainComposition]); diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 84bea7d385190c..812bc25d6d7727 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -9004,6 +9004,11 @@ static void VULKAN_Blit( VulkanTextureContainer *sourceTextureContainer = (VulkanTextureContainer *)source->textureSlice.texture; VkImageBlit region; + if ((sourceTextureContainer->activeTextureHandle->vulkanTexture->usageFlags & SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT) == 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Blit source texture must be created with SAMPLER bit!"); + return; + } + VulkanTextureSlice *srcTextureSlice = VULKAN_INTERNAL_FetchTextureSlice( sourceTextureContainer->activeTextureHandle->vulkanTexture, source->textureSlice.layer, diff --git a/test/testgpu_spinning_cube.c b/test/testgpu_spinning_cube.c index 64f350d371e168..14bb1d63100839 100644 --- a/test/testgpu_spinning_cube.c +++ b/test/testgpu_spinning_cube.c @@ -36,12 +36,13 @@ typedef struct RenderState { SDL_GpuBuffer *buf_vertex; SDL_GpuGraphicsPipeline *pipeline; + SDL_GpuSampleCount sample_count; } RenderState; typedef struct WindowState { int angle_x, angle_y, angle_z; - SDL_GpuTexture *tex_depth; + SDL_GpuTexture *tex_depth, *tex_msaa; Uint32 prev_drawablew, prev_drawableh; } WindowState; @@ -57,19 +58,15 @@ static void shutdownGpu(void) for (i = 0; i < state->num_windows; i++) { WindowState *winstate = &window_states[i]; SDL_GpuReleaseTexture(gpu_device, winstate->tex_depth); + SDL_GpuReleaseTexture(gpu_device, winstate->tex_msaa); SDL_GpuUnclaimWindow(gpu_device, state->windows[i]); } SDL_free(window_states); window_states = NULL; } - /* API FIXME: Should we gracefully handle NULL pointers being passed to these functions? */ - if (render_state.buf_vertex) { - SDL_GpuReleaseBuffer(gpu_device, render_state.buf_vertex); - } - if (render_state.pipeline) { - SDL_GpuReleaseGraphicsPipeline(gpu_device, render_state.pipeline); - } + SDL_GpuReleaseBuffer(gpu_device, render_state.buf_vertex); + SDL_GpuReleaseGraphicsPipeline(gpu_device, render_state.pipeline); SDL_GpuDestroyDevice(gpu_device); SDL_zero(render_state); @@ -262,7 +259,7 @@ CreateDepthTexture(Uint32 drawablew, Uint32 drawableh) depthtex_createinfo.isCube = 0; depthtex_createinfo.layerCount = 1; depthtex_createinfo.levelCount = 1; - depthtex_createinfo.sampleCount = SDL_GPU_SAMPLECOUNT_1; + depthtex_createinfo.sampleCount = render_state.sample_count; depthtex_createinfo.usageFlags = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT; result = SDL_GpuCreateTexture(gpu_device, &depthtex_createinfo); @@ -271,11 +268,37 @@ CreateDepthTexture(Uint32 drawablew, Uint32 drawableh) return result; } +static SDL_GpuTexture* +CreateMSAATexture(Uint32 drawablew, Uint32 drawableh) +{ + SDL_GpuTextureCreateInfo msaatex_createinfo; + SDL_GpuTexture *result; + + if (render_state.sample_count == SDL_GPU_SAMPLECOUNT_1) { + return NULL; + } + + msaatex_createinfo.width = drawablew; + msaatex_createinfo.height = drawableh; + msaatex_createinfo.depth = 1; + msaatex_createinfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8; + msaatex_createinfo.isCube = 0; + msaatex_createinfo.layerCount = 1; + msaatex_createinfo.levelCount = 1; + msaatex_createinfo.sampleCount = SDL_GPU_SAMPLECOUNT_4; + msaatex_createinfo.usageFlags = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT | SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT; + + result = SDL_GpuCreateTexture(gpu_device, &msaatex_createinfo); + CHECK_CREATE(result, "MSAA Texture") + + return result; +} + static void Render(SDL_Window *window, const int windownum) { WindowState *winstate = &window_states[windownum]; - SDL_GpuTexture *backbuffer; + SDL_GpuTexture *swapchain; SDL_GpuColorAttachmentInfo color_attachment; SDL_GpuDepthStencilAttachmentInfo depth_attachment; float matrix_rotate[16], matrix_modelview[16], matrix_perspective[16], matrix_final[16]; @@ -283,13 +306,15 @@ Render(SDL_Window *window, const int windownum) SDL_GpuCommandBuffer *cmd; SDL_GpuRenderPass *pass; SDL_GpuBufferBinding vertex_binding; + SDL_GpuTextureRegion src_region; + SDL_GpuTextureRegion dst_region; /* Acquire the swapchain texture */ cmd = SDL_GpuAcquireCommandBuffer(gpu_device); - backbuffer = SDL_GpuAcquireSwapchainTexture(cmd, state->windows[windownum], &drawablew, &drawableh); + swapchain = SDL_GpuAcquireSwapchainTexture(cmd, state->windows[windownum], &drawablew, &drawableh); - if (!backbuffer) { + if (!swapchain) { /* No swapchain was acquired, probably too many frames in flight */ SDL_GpuSubmit(cmd); return; @@ -329,7 +354,9 @@ Render(SDL_Window *window, const int windownum) if (winstate->prev_drawablew != drawablew || winstate->prev_drawableh != drawableh) { SDL_GpuReleaseTexture(gpu_device, winstate->tex_depth); + SDL_GpuReleaseTexture(gpu_device, winstate->tex_msaa); winstate->tex_depth = CreateDepthTexture(drawablew, drawableh); + winstate->tex_msaa = CreateMSAATexture(drawablew, drawableh); } winstate->prev_drawablew = drawablew; winstate->prev_drawableh = drawableh; @@ -340,7 +367,7 @@ Render(SDL_Window *window, const int windownum) color_attachment.clearColor.a = 1.0f; color_attachment.loadOp = SDL_GPU_LOADOP_CLEAR; color_attachment.storeOp = SDL_GPU_STOREOP_STORE; - color_attachment.textureSlice.texture = backbuffer; + color_attachment.textureSlice.texture = winstate->tex_msaa ? winstate->tex_msaa : swapchain; SDL_zero(depth_attachment); depth_attachment.depthStencilClearValue.depth = 1.0f; @@ -364,6 +391,20 @@ Render(SDL_Window *window, const int windownum) SDL_GpuDrawPrimitives(pass, 0, 12); SDL_GpuEndRenderPass(pass); + /* Blit MSAA to swapchain, if needed */ + if (render_state.sample_count > SDL_GPU_SAMPLECOUNT_1) { + SDL_zero(src_region); + src_region.textureSlice.texture = winstate->tex_msaa; + src_region.w = drawablew; + src_region.h = drawableh; + src_region.d = 1; + + dst_region = src_region; + dst_region.textureSlice.texture = swapchain; + + SDL_GpuBlit(cmd, &src_region, &dst_region, SDL_GPU_FILTER_LINEAR, SDL_FALSE); + } + /* Submit the command buffer! */ SDL_GpuSubmit(cmd); @@ -407,7 +448,7 @@ load_shader(SDL_bool is_vertex) } static void -init_render_state(void) +init_render_state(int msaa) { SDL_GpuCommandBuffer *cmd; SDL_GpuTransferBuffer *buf_transfer; @@ -482,11 +523,19 @@ init_render_state(void) SDL_GpuReleaseTransferBuffer(gpu_device, buf_transfer); + /* Determine which sample count to use */ + render_state.sample_count = msaa ? SDL_GPU_SAMPLECOUNT_4 : SDL_GPU_SAMPLECOUNT_1; + /* Set up the graphics pipeline */ SDL_zero(pipelinedesc); - color_attachment_desc.format = SDL_GpuGetSwapchainTextureFormat(gpu_device, state->windows[0]); + if (msaa) { + color_attachment_desc.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8; + } else { + color_attachment_desc.format = SDL_GpuGetSwapchainTextureFormat(gpu_device, state->windows[0]); + } + color_attachment_desc.blendState.blendEnable = 0; color_attachment_desc.blendState.alphaBlendOp = SDL_GPU_BLENDOP_ADD; color_attachment_desc.blendState.colorBlendOp = SDL_GPU_BLENDOP_ADD; @@ -505,7 +554,9 @@ init_render_state(void) pipelinedesc.depthStencilState.depthWriteEnable = 1; pipelinedesc.depthStencilState.compareOp = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; + pipelinedesc.multisampleState.multisampleCount = render_state.sample_count; pipelinedesc.multisampleState.sampleMask = 0xF; + pipelinedesc.primitiveType = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; pipelinedesc.vertexShader = vertex_shader; @@ -552,6 +603,7 @@ init_render_state(void) /* create a depth texture for the window */ SDL_GetWindowSizeInPixels(state->windows[i], (int*) &drawablew, (int*) &drawableh); winstate->tex_depth = CreateDepthTexture(drawablew, drawableh); + winstate->tex_msaa = CreateMSAATexture(drawablew, drawableh); /* make each window different */ winstate->angle_x = (i * 10) % 360; @@ -586,18 +638,37 @@ void loop() int main(int argc, char *argv[]) { + int msaa; + int i; const SDL_DisplayMode *mode; Uint32 then, now; + /* Initialize params */ + msaa = 0; + /* Initialize test framework */ state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); if (!state) { return 1; } - - /* Parse commandline */ - if (!SDLTest_CommonDefaultArgs(state, argc, argv)) { - return 1; + for (i = 1; i < argc;) { + int consumed; + + consumed = SDLTest_CommonArg(state, i); + if (consumed == 0) { + if (SDL_strcasecmp(argv[i], "--msaa") == 0) { + ++msaa; + consumed = 1; + } else { + consumed = -1; + } + } + if (consumed < 0) { + static const char *options[] = { "[--msaa]", NULL }; + SDLTest_CommonLogUsage(state, argv[0], options); + quit(1); + } + i += consumed; } state->skip_renderer = 1; @@ -611,7 +682,7 @@ main(int argc, char *argv[]) mode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(state->windows[0])); SDL_Log("Screen bpp: %d\n", SDL_BITSPERPIXEL(mode->format)); - init_render_state(); + init_render_state(msaa); /* Main render loop */ frames = 0;