diff --git a/include/Refresh.h b/include/Refresh.h index 3421417..3ef21e9 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -98,7 +98,7 @@ typedef enum REFRESH_StoreOp typedef enum REFRESH_ClearOptions { - REFRESH_CLEAROPTIONS_TARGET = 1, + REFRESH_CLEAROPTIONS_COLOR = 1, REFRESH_CLEAROPTIONS_DEPTH = 2, REFRESH_CLEAROPTIONS_STENCIL = 4, } REFRESH_ClearOptions; @@ -619,21 +619,26 @@ REFRESHAPI void REFRESH_DestroyDevice(REFRESH_Device *device); /* Drawing */ /* Clears the targets of the currently bound framebuffer. + * If fewer colors are passed than the number of color targets in the + * framebuffer, this function will clear the first n color targets. + * * NOTE: * It is generally recommended to clear in BeginRenderPass - * rather than by calling this function. + * rather than by calling this function unless necessary. * - * options: Bitflags to specify color/depth/stencil buffers for clearing. - * colors: The new values of the cleared color buffers. - * colorCount: The amount of cleared color buffers. - * depth: The new value of the cleared depth buffer. - * stencil: The new value of the cleared stencil buffer. + * clearRect: Area to clear. + * options: Bitflags to specify color/depth/stencil buffers for clearing. + * colors: An array of color values for the cleared color buffers. + * colorCount: The number of colors in the above array. + * depth: The new value of the cleared depth buffer. + * stencil: The new value of the cleared stencil buffer. */ REFRESHAPI void REFRESH_Clear( REFRESH_Device *device, + REFRESH_Rect *clearRect, REFRESH_ClearOptions options, - REFRESH_Vec4 **colors, - uint32_t colorCount, + REFRESH_Color *colors, + uint32_t colorCount, float depth, int32_t stencil ); diff --git a/src/Refresh.c b/src/Refresh.c index 4ce255d..6cf040a 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -149,14 +149,23 @@ void REFRESH_DestroyDevice(REFRESH_Device *device) void REFRESH_Clear( REFRESH_Device *device, + REFRESH_Rect *clearRect, REFRESH_ClearOptions options, - REFRESH_Vec4 **colors, - uint32_t colorCount, + REFRESH_Color *colors, + uint32_t colorCount, float depth, int32_t stencil ) { NULL_RETURN(device); - device->Clear(device->driverData, options, colors, colorCount, depth, stencil); + device->Clear( + device->driverData, + clearRect, + options, + colors, + colorCount, + depth, + stencil + ); } void REFRESH_DrawIndexedPrimitives( diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 64aef7b..9a09f9a 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -170,8 +170,9 @@ struct REFRESH_Device void (*Clear)( REFRESH_Renderer *driverData, + REFRESH_Rect *clearRect, REFRESH_ClearOptions options, - REFRESH_Vec4 **colors, + REFRESH_Color *colors, uint32_t colorCount, float depth, int32_t stencil diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 206fd07..b2326d2 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -738,6 +738,8 @@ typedef struct VulkanFramebuffer VulkanColorTarget *colorTargets[MAX_COLOR_TARGET_BINDINGS]; uint32_t colorTargetCount; VulkanDepthStencilTarget *depthStencilTarget; + uint32_t width; + uint32_t height; } VulkanFramebuffer; /* Cache structures */ @@ -3253,13 +3255,112 @@ static void VULKAN_DestroyDevice( static void VULKAN_Clear( REFRESH_Renderer *driverData, + REFRESH_Rect *clearRect, REFRESH_ClearOptions options, - REFRESH_Vec4 **colors, - uint32_t colorCount, + REFRESH_Color *colors, + uint32_t colorCount, float depth, int32_t stencil ) { - SDL_assert(0); + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + uint32_t attachmentCount, i; + VkClearAttachment clearAttachments[MAX_COLOR_TARGET_BINDINGS + 1]; + VkClearRect vulkanClearRect; + VkClearValue clearValues[4]; + + uint8_t shouldClearColor = options & REFRESH_CLEAROPTIONS_COLOR; + uint8_t shouldClearDepth = options & REFRESH_CLEAROPTIONS_DEPTH; + uint8_t shouldClearStencil = options & REFRESH_CLEAROPTIONS_STENCIL; + + uint8_t shouldClearDepthStencil = ( + (shouldClearDepth || shouldClearStencil) && + renderer->currentFramebuffer->depthStencilTarget != NULL + ); + + if (!shouldClearColor && !shouldClearDepthStencil) + { + return; + } + + vulkanClearRect.baseArrayLayer = 0; + vulkanClearRect.layerCount = 1; + vulkanClearRect.rect.offset.x = clearRect->x; + vulkanClearRect.rect.offset.y = clearRect->y; + vulkanClearRect.rect.extent.width = clearRect->w; + vulkanClearRect.rect.extent.height = clearRect->h; + + attachmentCount = 0; + + if (shouldClearColor) + { + for (i = 0; i < colorCount; i += 1) + { + clearValues[i].color.float32[0] = colors[i].r / 255.0f; + clearValues[i].color.float32[1] = colors[i].g / 255.0f; + clearValues[i].color.float32[2] = colors[i].b / 255.0f; + clearValues[i].color.float32[3] = colors[i].a / 255.0f; + } + + for (i = 0; i < colorCount; i += 1) + { + clearAttachments[attachmentCount].aspectMask = + VK_IMAGE_ASPECT_COLOR_BIT; + clearAttachments[attachmentCount].colorAttachment = + attachmentCount; + clearAttachments[attachmentCount].clearValue = + clearValues[attachmentCount]; + attachmentCount += 1; + + /* Do NOT clear the multisample image here! + * Vulkan treats them both as the same color attachment. + * Vulkan is a very good and not confusing at all API. + */ + } + } + + if (shouldClearDepthStencil) + { + clearAttachments[attachmentCount].aspectMask = 0; + clearAttachments[attachmentCount].colorAttachment = 0; + + if (shouldClearDepth) + { + if (depth < 0.0f) + { + depth = 0.0f; + } + else if (depth > 1.0f) + { + depth = 1.0f; + } + clearAttachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + clearAttachments[attachmentCount].clearValue.depthStencil.depth = depth; + } + else + { + clearAttachments[attachmentCount].clearValue.depthStencil.depth = 0.0f; + } + + if (shouldClearStencil) + { + clearAttachments[attachmentCount].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + clearAttachments[attachmentCount].clearValue.depthStencil.stencil = stencil; + } + else + { + clearAttachments[attachmentCount].clearValue.depthStencil.stencil = 0; + } + + attachmentCount += 1; + } + + RECORD_CMD(renderer->vkCmdClearAttachments( + renderer->currentCommandBuffer, + attachmentCount, + clearAttachments, + 1, + &vulkanClearRect + )); } static void VULKAN_DrawInstancedPrimitives( @@ -4474,6 +4575,9 @@ static REFRESH_Framebuffer* VULKAN_CreateFramebuffer( vulkanFramebuffer->depthStencilTarget = (VulkanDepthStencilTarget*) framebufferCreateInfo->pDepthStencilTarget; + vulkanFramebuffer->width = framebufferCreateInfo->width; + vulkanFramebuffer->height = framebufferCreateInfo->height; + SDL_stack_free(imageViews); return (REFRESH_Framebuffer*) vulkanFramebuffer; }