Implement cubemap sampling
This still uses the legacy approach with 6 pointers per mipmap level
for each cube face. Will be refactored to use a single pointer to access
faces as consecutive layers.
Bug: b/129523279
Tests: dEQP-VK.texture.filtering.cube.formats.r8g8b8a8_unorm.*
Change-Id: I1f59f121d2989e0ba79eb3441529b812a8d9111a
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29969
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp
index 03de441..9886bce 100644
--- a/src/Device/Renderer.cpp
+++ b/src/Device/Renderer.cpp
@@ -504,7 +504,7 @@
if(draw->renderTarget[index])
{
- data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0);
+ data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0);
data->colorPitchB[index] = context->renderTarget[index]->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
data->colorSliceB[index] = context->renderTarget[index]->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
}
@@ -515,14 +515,14 @@
if(draw->depthBuffer)
{
- data->depthBuffer = (float*)context->depthBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_DEPTH_BIT, 0);
+ data->depthBuffer = (float*)context->depthBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
data->depthPitchB = context->depthBuffer->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
data->depthSliceB = context->depthBuffer->slicePitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
}
if(draw->stencilBuffer)
{
- data->stencilBuffer = (unsigned char*)context->stencilBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_STENCIL_BIT, 0);
+ data->stencilBuffer = (unsigned char*)context->stencilBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0);
data->stencilPitchB = context->stencilBuffer->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
data->stencilSliceB = context->stencilBuffer->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
}
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index 2d675d6..377d10a 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -24,16 +24,17 @@
{
switch(swizzle)
{
- case VK_COMPONENT_SWIZZLE_R: f = c.x; break;
- case VK_COMPONENT_SWIZZLE_G: f = c.y; break;
- case VK_COMPONENT_SWIZZLE_B: f = c.z; break;
- case VK_COMPONENT_SWIZZLE_A: f = c.w; break;
- case VK_COMPONENT_SWIZZLE_ZERO: f = sw::Float4(0.0f, 0.0f, 0.0f, 0.0f); break;
+ case VK_COMPONENT_SWIZZLE_R: f = c.x; break;
+ case VK_COMPONENT_SWIZZLE_G: f = c.y; break;
+ case VK_COMPONENT_SWIZZLE_B: f = c.z; break;
+ case VK_COMPONENT_SWIZZLE_A: f = c.w; break;
+ case VK_COMPONENT_SWIZZLE_ZERO: f = sw::Float4(0.0f, 0.0f, 0.0f, 0.0f); break;
case VK_COMPONENT_SWIZZLE_ONE:
if (integer)
{
- f = rr::As<sw::Float4>(sw::Int4(1.0f, 1.0f, 1.0f, 1.0f));
- } else
+ f = rr::As<sw::Float4>(sw::Int4(1, 1, 1, 1));
+ }
+ else
{
f = sw::Float4(1.0f, 1.0f, 1.0f, 1.0f);
}
@@ -127,7 +128,7 @@
{
Vector4s cs = sampleFilter(texture, uuuu, vvvv, wwww, offset, lod, anisotropy, uDelta, vDelta, face, function);
- if(state.textureFormat == VK_FORMAT_R5G6B5_UNORM_PACK16)
+ if(state.textureFormat == VK_FORMAT_R5G6B5_UNORM_PACK16)
{
c.x = Float4(As<UShort4>(cs.x)) * Float4(1.0f / 0xF800);
c.y = Float4(As<UShort4>(cs.y)) * Float4(1.0f / 0xFC00);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 2068bcc..995a47a 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -879,7 +879,7 @@
static sw::TextureType convertTextureType(VkImageViewType imageViewType);
static sw::FilterType convertFilterMode(const vk::Sampler *sampler);
static sw::MipmapType convertMipmapMode(const vk::Sampler *sampler);
- static sw::AddressingMode convertAddressingMode(VkSamplerAddressMode);
+ static sw::AddressingMode convertAddressingMode(VkSamplerAddressMode addressMode, VkImageViewType imageViewType);
};
class SpirvRoutine
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index ea4a802..593cdbb 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -43,6 +43,7 @@
{
return getImageSampler(Implicit, imageView, sampler);
}
+
SpirvShader::ImageSampler *SpirvShader::getImageSamplerExplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler)
{
return getImageSampler(Lod, imageView, sampler);
@@ -83,9 +84,9 @@
samplerState.textureFormat = imageView->getFormat();
samplerState.textureFilter = convertFilterMode(sampler);
- samplerState.addressingModeU = convertAddressingMode(sampler->addressModeU);
- samplerState.addressingModeV = convertAddressingMode(sampler->addressModeV);
- samplerState.addressingModeW = convertAddressingMode(sampler->addressModeW);
+ samplerState.addressingModeU = convertAddressingMode(sampler->addressModeU, imageView->getType());
+ samplerState.addressingModeV = convertAddressingMode(sampler->addressModeV, imageView->getType());
+ samplerState.addressingModeW = convertAddressingMode(sampler->addressModeW, imageView->getType());
samplerState.mipmapFilter = convertMipmapMode(sampler);
samplerState.sRGB = imageView->getFormat().isSRGBformat();
samplerState.swizzle = imageView->getComponentMapping();
@@ -102,8 +103,7 @@
SamplerCore s(constants, samplerState);
Pointer<Byte> texture = image + OFFSET(vk::SampledImageDescriptor, texture); // sw::Texture*
- SIMD::Float uv[2];
- SIMD::Float w(0); // TODO(b/129523279)
+ SIMD::Float uvw[3];
SIMD::Float q(0); // TODO(b/129523279)
SIMD::Float bias(0);
Vector4f dsx; // TODO(b/129523279)
@@ -111,22 +111,31 @@
Vector4f offset; // TODO(b/129523279)
SamplerFunction samplerFunction = { samplerMethod, None }; // TODO(b/129523279)
- // TODO(b/129523279): Currently 1D textures are treated as 2D by setting the second coordinate to 0.
- // Implement optimized 1D sampling.
- uv[1] = SIMD::Float(0);
-
int coordinateCount = 0;
switch(imageView->getType())
{
- case VK_IMAGE_VIEW_TYPE_1D: coordinateCount = 1; break;
- case VK_IMAGE_VIEW_TYPE_2D: coordinateCount = 2; break;
+ case VK_IMAGE_VIEW_TYPE_1D: coordinateCount = 1; break;
+ case VK_IMAGE_VIEW_TYPE_2D: coordinateCount = 2; break;
+// case VK_IMAGE_VIEW_TYPE_3D: coordinateCount = 3; break;
+ case VK_IMAGE_VIEW_TYPE_CUBE: coordinateCount = 3; break;
+// case VK_IMAGE_VIEW_TYPE_1D_ARRAY: coordinateCount = 2; break;
+// case VK_IMAGE_VIEW_TYPE_2D_ARRAY: coordinateCount = 3; break;
+// case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: coordinateCount = 4; break;
default:
UNIMPLEMENTED("imageView type %d", imageView->getType());
}
for(int i = 0; i < coordinateCount; i++)
{
- uv[i] = in[i];
+ uvw[i] = in[i];
+ }
+
+ // TODO(b/129523279): Currently 1D textures are treated as 2D by setting the second coordinate to 0.
+ // Implement optimized 1D sampling.
+ If(imageView->getType() == VK_IMAGE_VIEW_TYPE_1D ||
+ imageView->getType() == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
+ {
+ uvw[1] = SIMD::Float(0);
}
if(samplerMethod == Lod)
@@ -136,7 +145,7 @@
bias = in[coordinateCount];
}
- Vector4f sample = s.sampleTexture(texture, uv[0], uv[1], w, q, bias, dsx, dsy, offset, samplerFunction);
+ Vector4f sample = s.sampleTexture(texture, uvw[0], uvw[1], uvw[2], q, bias, dsx, dsy, offset, samplerFunction);
Pointer<SIMD::Float> rgba = out;
rgba[0] = sample.x;
@@ -152,7 +161,7 @@
case VK_IMAGE_VIEW_TYPE_1D: return TEXTURE_1D;
case VK_IMAGE_VIEW_TYPE_2D: return TEXTURE_2D;
// case VK_IMAGE_VIEW_TYPE_3D: return TEXTURE_3D;
-// case VK_IMAGE_VIEW_TYPE_CUBE: return TEXTURE_CUBE;
+ case VK_IMAGE_VIEW_TYPE_CUBE: return TEXTURE_CUBE;
// case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return TEXTURE_1D_ARRAY;
// case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return TEXTURE_2D_ARRAY;
// case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return TEXTURE_CUBE_ARRAY;
@@ -204,8 +213,29 @@
}
}
-sw::AddressingMode SpirvShader::convertAddressingMode(VkSamplerAddressMode addressMode)
+sw::AddressingMode SpirvShader::convertAddressingMode(VkSamplerAddressMode addressMode, VkImageViewType imageViewType)
{
+ // Vulkan 1.1 spec:
+ // "Cube images ignore the wrap modes specified in the sampler. Instead, if VK_FILTER_NEAREST is used within a mip level then
+ // VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE is used, and if VK_FILTER_LINEAR is used within a mip level then sampling at the edges
+ // is performed as described earlier in the Cube map edge handling section."
+ // This corresponds with our 'seamless' addressing mode.
+ switch(imageViewType)
+ {
+ case VK_IMAGE_VIEW_TYPE_CUBE:
+ case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
+ return ADDRESSING_SEAMLESS;
+ case VK_IMAGE_VIEW_TYPE_1D:
+ case VK_IMAGE_VIEW_TYPE_2D:
+// case VK_IMAGE_VIEW_TYPE_3D:
+// case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
+// case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
+ break;
+ default:
+ UNIMPLEMENTED("imageViewType %d", imageViewType);
+ return ADDRESSING_WRAP;
+ }
+
switch(addressMode)
{
case VK_SAMPLER_ADDRESS_MODE_REPEAT: return ADDRESSING_WRAP;
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index 5442e45..a383c22 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -301,12 +301,26 @@
int level = mipmapLevel - baseLevel; // Level within the image view
level = sw::clamp(level, 0, (int)subresourceRange.levelCount - 1);
- VkOffset3D offset = {0, 0, 0};
VkImageAspectFlagBits aspect = VK_IMAGE_ASPECT_COLOR_BIT;
- void *buffer = imageView->getOffsetPointer(offset, aspect, level);
-
sw::Mipmap &mipmap = texture->mipmap[mipmapLevel];
- mipmap.buffer[0] = buffer;
+
+ if(imageView->getType() == VK_IMAGE_VIEW_TYPE_CUBE)
+ {
+ for(int face = 0; face < 6; face++)
+ {
+ // Obtain the pointer to the corner of the level including the border, for seamless sampling.
+ // This is taken into account in the sampling routine, which can't handle negative texel coordinates.
+ VkOffset3D offset = {-1, -1, 0};
+
+ // TODO(b/129523279): Implement as 6 consecutive layers instead of separate pointers.
+ mipmap.buffer[face] = imageView->getOffsetPointer(offset, aspect, level, face);
+ }
+ }
+ else
+ {
+ VkOffset3D offset = {0, 0, 0};
+ mipmap.buffer[0] = imageView->getOffsetPointer(offset, aspect, level, 0);
+ }
VkExtent3D extent = imageView->getMipLevelExtent(level);
Format format = imageView->getFormat();
@@ -445,7 +459,7 @@
{
auto update = reinterpret_cast<VkDescriptorImageInfo const *>(src + entry.offset + entry.stride * i);
auto imageView = Cast(update->imageView);
- descriptor[i].ptr = imageView->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0);
+ descriptor[i].ptr = imageView->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0);
descriptor[i].extent = imageView->getMipLevelExtent(0);
descriptor[i].rowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
descriptor[i].slicePitchBytes = imageView->getSubresourceRange().layerCount > 1
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index 65e1245..23f79c8 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -171,7 +171,7 @@
image->copyTo(*(resolveAttachment->image), region);
}
-void *ImageView::getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel) const
+void *ImageView::getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const
{
ASSERT(mipLevel < subresourceRange.levelCount);
@@ -179,7 +179,7 @@
{
static_cast<VkImageAspectFlags>(aspect),
subresourceRange.baseMipLevel + mipLevel,
- subresourceRange.baseArrayLayer,
+ subresourceRange.baseArrayLayer + layer,
subresourceRange.layerCount
};
return image->getTexelPointer(offset, imageSubresourceLayers);
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp
index 96d7760..fad7bfb 100644
--- a/src/Vulkan/VkImageView.hpp
+++ b/src/Vulkan/VkImageView.hpp
@@ -46,7 +46,7 @@
int layerPitchBytes(VkImageAspectFlagBits aspect) const { return static_cast<int>(image->getLayerSize(aspect)); }
VkExtent3D getMipLevelExtent(uint32_t mipLevel) const { return image->getMipLevelExtent(subresourceRange.baseMipLevel + mipLevel); }
- void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel) const;
+ void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const;
bool hasDepthAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; }
bool hasStencilAspect() const { return (subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; }