Allow the Blitter to clear and blit vk::Image objects directly The sw::Surface object was the intermediate representation of an image used between the vk::Image and the Blitter. This cl removes the need for an intermediate representation by having the Blitter use the vk::Image directly. There should be no regression for the clear and blit tests. Bug b/126883332 Change-Id: Icbc15470e3ad112ed78f4f62d6d82c66e3e37a20 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/25928 Tested-by: Alexis Hétu <sugoi@google.com> Presubmit-Ready: Alexis Hétu <sugoi@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp index b86e4f9..4e42bd3 100644 --- a/src/Device/Blitter.cpp +++ b/src/Device/Blitter.cpp
@@ -18,6 +18,7 @@ #include "Reactor/Reactor.hpp" #include "System/Memory.hpp" #include "Vulkan/VkDebug.hpp" +#include "Vulkan/VkImage.hpp" namespace sw { @@ -44,6 +45,203 @@ delete color; } + void Blitter::clear(void *pixel, VkFormat format, vk::Image *dest, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea) + { + VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask); + if(dest->getFormat(aspect) == VK_FORMAT_UNDEFINED) + { + return; + } + + if(fastClear(pixel, format, dest, subresourceRange, renderArea)) + { + return; + } + + State state(format, dest->getFormat(aspect), dest->getSampleCountFlagBits(), { 0xF }); + Routine *blitRoutine = getRoutine(state); + if(!blitRoutine) + { + return; + } + + void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry(); + + VkImageSubresourceLayers subresLayers = + { + subresourceRange.aspectMask, + subresourceRange.baseMipLevel, + subresourceRange.baseArrayLayer, + 1 + }; + + uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange); + uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange); + + VkRect2D area = { { 0, 0 }, { 0, 0 } }; + if(renderArea) + { + ASSERT(subresourceRange.levelCount == 1); + area = *renderArea; + } + + for(; subresLayers.mipLevel <= lastMipLevel; subresLayers.mipLevel++) + { + VkExtent3D extent = dest->getMipLevelExtent(subresLayers.mipLevel); + if(!renderArea) + { + area.extent.width = extent.width; + area.extent.height = extent.height; + } + + BlitData data = + { + pixel, nullptr, // source, dest + + sw::Surface::bytes(format), // sPitchB + dest->rowPitchBytes(aspect, subresLayers.mipLevel), // dPitchB + dest->slicePitchBytes(aspect, subresLayers.mipLevel), // dSliceB + + 0.5f, 0.5f, 0.0f, 0.0f, // x0, y0, w, h + + area.offset.y, static_cast<int>(area.offset.y + area.extent.height), // y0d, y1d + area.offset.x, static_cast<int>(area.offset.x + area.extent.width), // x0d, x1d + + 0, 0, // sWidth, sHeight + }; + + for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++) + { + for(uint32_t depth = 0; depth < extent.depth; depth++) + { + data.dest = dest->getTexelPointer({ 0, 0, static_cast<int32_t>(depth) }, subresLayers); + + blitFunction(&data); + } + } + } + } + + bool Blitter::fastClear(void *pixel, VkFormat format, vk::Image *dest, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea) + { + if(format != VK_FORMAT_R32G32B32A32_SFLOAT) + { + return false; + } + + float *color = (float*)pixel; + float r = color[0]; + float g = color[1]; + float b = color[2]; + float a = color[3]; + + uint32_t packed; + + VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask); + switch(dest->getFormat(aspect)) + { + case VK_FORMAT_R5G6B5_UNORM_PACK16: + packed = ((uint16_t)(31 * b + 0.5f) << 0) | + ((uint16_t)(63 * g + 0.5f) << 5) | + ((uint16_t)(31 * r + 0.5f) << 11); + break; + case VK_FORMAT_B5G6R5_UNORM_PACK16: + packed = ((uint16_t)(31 * r + 0.5f) << 0) | + ((uint16_t)(63 * g + 0.5f) << 5) | + ((uint16_t)(31 * b + 0.5f) << 11); + break; + case VK_FORMAT_A8B8G8R8_UINT_PACK32: + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + case VK_FORMAT_R8G8B8A8_UNORM: + packed = ((uint32_t)(255 * a + 0.5f) << 24) | + ((uint32_t)(255 * b + 0.5f) << 16) | + ((uint32_t)(255 * g + 0.5f) << 8) | + ((uint32_t)(255 * r + 0.5f) << 0); + break; + case VK_FORMAT_B8G8R8A8_UNORM: + packed = ((uint32_t)(255 * a + 0.5f) << 24) | + ((uint32_t)(255 * r + 0.5f) << 16) | + ((uint32_t)(255 * g + 0.5f) << 8) | + ((uint32_t)(255 * b + 0.5f) << 0); + break; + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + packed = R11G11B10F(color); + break; + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + packed = RGB9E5(color); + break; + default: + return false; + } + + VkImageSubresourceLayers subresLayers = + { + subresourceRange.aspectMask, + subresourceRange.baseMipLevel, + subresourceRange.baseArrayLayer, + 1 + }; + uint32_t lastMipLevel = dest->getLastMipLevel(subresourceRange); + uint32_t lastLayer = dest->getLastLayerIndex(subresourceRange); + + VkRect2D area = { { 0, 0 }, { 0, 0 } }; + if(renderArea) + { + ASSERT(subresourceRange.levelCount == 1); + area = *renderArea; + } + + for(; subresLayers.mipLevel <= lastMipLevel; subresLayers.mipLevel++) + { + int rowPitchBytes = dest->rowPitchBytes(aspect, subresLayers.mipLevel); + int slicePitchBytes = dest->slicePitchBytes(aspect, subresLayers.mipLevel); + VkExtent3D extent = dest->getMipLevelExtent(subresLayers.mipLevel); + if(!renderArea) + { + area.extent.width = extent.width; + area.extent.height = extent.height; + } + + for(subresLayers.baseArrayLayer = subresourceRange.baseArrayLayer; subresLayers.baseArrayLayer <= lastLayer; subresLayers.baseArrayLayer++) + { + for(uint32_t depth = 0; depth < extent.depth; depth++) + { + uint8_t *slice = (uint8_t*)dest->getTexelPointer( + { area.offset.x, area.offset.y, static_cast<int32_t>(depth) }, subresLayers); + + for(int j = 0; j < dest->getSampleCountFlagBits(); j++) + { + uint8_t *d = slice; + + switch(Surface::bytes(dest->getFormat(aspect))) + { + case 2: + for(uint32_t i = 0; i < area.extent.height; i++) + { + sw::clear((uint16_t*)d, packed, area.extent.width); + d += rowPitchBytes; + } + break; + case 4: + for(uint32_t i = 0; i < area.extent.height; i++) + { + sw::clear((uint32_t*)d, packed, area.extent.width); + d += rowPitchBytes; + } + break; + default: + assert(false); + } + + slice += slicePitchBytes; + } + } + } + } + + return true; + } + bool Blitter::fastClear(void *pixel, VkFormat format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask) { if(format != VK_FORMAT_R32G32B32A32_SFLOAT) @@ -1628,6 +1826,30 @@ return function("BlitRoutine"); } + Routine *Blitter::getRoutine(const State &state) + { + criticalSection.lock(); + Routine *blitRoutine = blitCache->query(state); + + if(!blitRoutine) + { + blitRoutine = generate(state); + + if(!blitRoutine) + { + criticalSection.unlock(); + UNIMPLEMENTED(); + return nullptr; + } + + blitCache->add(state, blitRoutine); + } + + criticalSection.unlock(); + + return blitRoutine; + } + bool Blitter::blitReactor(Surface *source, const SliceRectF &sourceRect, Surface *dest, const SliceRect &destRect, const Blitter::Options &options) { ASSERT(!options.clearOperation || ((source->getWidth() == 1) && (source->getHeight() == 1) && (source->getDepth() == 1))); @@ -1659,24 +1881,12 @@ state.destFormat = isStencil ? dest->getStencilFormat() : dest->getFormat(useDestInternal); state.destSamples = dest->getSamples(); - criticalSection.lock(); - Routine *blitRoutine = blitCache->query(state); - + Routine *blitRoutine = getRoutine(state); if(!blitRoutine) { - blitRoutine = generate(state); - - if(!blitRoutine) - { - criticalSection.unlock(); - return false; - } - - blitCache->add(state, blitRoutine); + return false; } - criticalSection.unlock(); - void (*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry(); BlitData data; @@ -1720,4 +1930,90 @@ return true; } + + void Blitter::blit(vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter) + { + if(dst->getFormat() == VK_FORMAT_UNDEFINED) + { + return; + } + + if((region.srcSubresource.baseArrayLayer != 0) || + (region.dstSubresource.baseArrayLayer != 0) || + (region.srcSubresource.layerCount != 1) || + (region.dstSubresource.layerCount != 1) || + (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask)) + { + UNIMPLEMENTED(); + } + + if(region.dstOffsets[0].x > region.dstOffsets[1].x) + { + swap(region.srcOffsets[0].x, region.srcOffsets[1].x); + swap(region.dstOffsets[0].x, region.dstOffsets[1].x); + } + + if(region.dstOffsets[0].y > region.dstOffsets[1].y) + { + swap(region.srcOffsets[0].y, region.srcOffsets[1].y); + swap(region.dstOffsets[0].y, region.dstOffsets[1].y); + } + + VkExtent3D srcExtent = src->getMipLevelExtent(region.srcSubresource.mipLevel); + VkExtent3D dstExtent = dst->getMipLevelExtent(region.dstSubresource.mipLevel); + + int32_t numSlices = (region.srcOffsets[1].z - region.srcOffsets[0].z); + ASSERT(numSlices == (region.dstOffsets[1].z - region.dstOffsets[0].z)); + + VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask); + VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask); + + State state(src->getFormat(srcAspect), dst->getFormat(dstAspect), dst->getSampleCountFlagBits(), + { filter != VK_FILTER_NEAREST, region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT, false }); + state.clampToEdge = (region.srcOffsets[0].x < 0) || + (region.srcOffsets[0].y < 0) || + (static_cast<uint32_t>(region.srcOffsets[1].x) > srcExtent.width) || + (static_cast<uint32_t>(region.srcOffsets[1].y) > srcExtent.height); + + Routine *blitRoutine = getRoutine(state); + if(!blitRoutine) + { + return; + } + + void(*blitFunction)(const BlitData *data) = (void(*)(const BlitData*))blitRoutine->getEntry(); + + BlitData data; + + data.sPitchB = src->rowPitchBytes(srcAspect, region.srcSubresource.mipLevel); + data.dPitchB = dst->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel); + data.dSliceB = dst->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel); + + data.w = static_cast<float>(region.srcOffsets[1].x - region.srcOffsets[0].x) / + static_cast<float>(region.dstOffsets[1].x - region.dstOffsets[0].x); + data.h = static_cast<float>(region.srcOffsets[1].y - region.srcOffsets[0].y) / + static_cast<float>(region.dstOffsets[1].y - region.dstOffsets[0].y); + data.x0 = region.srcOffsets[0].x + (0.5f - region.dstOffsets[0].x) * data.w; + data.y0 = region.srcOffsets[0].y + (0.5f - region.dstOffsets[0].y) * data.h; + + data.x0d = region.dstOffsets[0].x; + data.x1d = region.dstOffsets[1].x; + data.y0d = region.dstOffsets[0].y; + data.y1d = region.dstOffsets[1].y; + + data.sWidth = srcExtent.width; + data.sHeight = srcExtent.height; + + VkOffset3D srcOffset = { 0, 0, region.srcOffsets[0].z }; + VkOffset3D dstOffset = { 0, 0, region.dstOffsets[0].z }; + + for(int i = 0; i < numSlices; i++) + { + data.source = src->getTexelPointer(srcOffset, region.srcSubresource); + data.dest = dst->getTexelPointer(dstOffset, region.dstSubresource); + blitFunction(&data); + srcOffset.z++; + dstOffset.z++; + } + } }
diff --git a/src/Device/Blitter.hpp b/src/Device/Blitter.hpp index 637a5f8..6717fb1 100644 --- a/src/Device/Blitter.hpp +++ b/src/Device/Blitter.hpp
@@ -21,6 +21,11 @@ #include <string.h> +namespace vk +{ + class Image; +} + namespace sw { class Blitter @@ -57,6 +62,8 @@ { State() = default; State(const Options &options) : Options(options) {} + State(VkFormat sourceFormat, VkFormat destFormat, int destSamples, const Options &options) : + Options(options), sourceFormat(sourceFormat), destFormat(destFormat), destSamples(destSamples) {} bool operator==(const State &state) const { @@ -95,11 +102,15 @@ virtual ~Blitter(); void clear(void *pixel, VkFormat format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask); + void clear(void *pixel, VkFormat format, vk::Image *dest, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea = nullptr); + void blit(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, const Options &options); + void blit(vk::Image *src, vk::Image *dst, VkImageBlit region, VkFilter filter); void blit3D(Surface *source, Surface *dest); private: bool fastClear(void *pixel, VkFormat format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask); + bool fastClear(void *pixel, VkFormat format, vk::Image *dest, const VkImageSubresourceRange& subresourceRange, const VkRect2D* renderArea); bool read(Float4 &color, Pointer<Byte> element, const State &state); bool write(Float4 &color, Pointer<Byte> element, const State &state); @@ -111,6 +122,7 @@ static Float4 LinearToSRGB(Float4 &color); static Float4 sRGBtoLinear(Float4 &color); bool blitReactor(Surface *source, const SliceRectF &sRect, Surface *dest, const SliceRect &dRect, const Options &options); + Routine *getRoutine(const State &state); Routine *generate(const State &state); RoutineCache<State> *blitCache;