Implement basic SPIR-V texture sampling
Replaces VkDescriptorImageInfo with a more concrete
SampledImageDescriptor, which contains an sw::Texture that SamplerCore
uses.
The parameters can be looked up statically only because the
shaderSampledImageArrayDynamicIndexing feature is currently not
supported.
Bug b/129523279
Test: dEQP-VK.texture.filtering.2d.formats.r8g8b8a8_unorm.nearest
Change-Id: I619b5b48b2b4552d9bfc70b087df2c31eabb49ea
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28434
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp
index 983faae..245f219 100644
--- a/src/Device/Renderer.cpp
+++ b/src/Device/Renderer.cpp
@@ -510,8 +510,8 @@
{
VkOffset3D offset = { 0, 0, static_cast<int32_t>(context->renderTargetLayer[index]) };
data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->getOffsetPointer(offset, VK_IMAGE_ASPECT_COLOR_BIT);
- data->colorPitchB[index] = context->renderTarget[index]->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT);
- data->colorSliceB[index] = context->renderTarget[index]->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT);
+ 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);
}
}
@@ -522,16 +522,16 @@
{
VkOffset3D offset = { 0, 0, static_cast<int32_t>(context->depthBufferLayer) };
data->depthBuffer = (float*)context->depthBuffer->getOffsetPointer(offset, VK_IMAGE_ASPECT_DEPTH_BIT);
- data->depthPitchB = context->depthBuffer->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT);
- data->depthSliceB = context->depthBuffer->slicePitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT);
+ 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)
{
VkOffset3D offset = { 0, 0, static_cast<int32_t>(context->stencilBufferLayer) };
data->stencilBuffer = (unsigned char*)context->stencilBuffer->getOffsetPointer(offset, VK_IMAGE_ASPECT_STENCIL_BIT);
- data->stencilPitchB = context->stencilBuffer->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT);
- data->stencilSliceB = context->stencilBuffer->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT);
+ data->stencilPitchB = context->stencilBuffer->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
+ data->stencilSliceB = context->stencilBuffer->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
}
}
@@ -881,9 +881,9 @@
query->state = vk::Query::FINISHED;
}
- // Manual unlocking is done before notifying, to avoid
- // waking up the waiting thread only to block again
- mutexLock.unlock();
+ // Manual unlocking is done before notifying, to avoid
+ // waking up the waiting thread only to block again
+ mutexLock.unlock();
query->condition.notify_one();
}
diff --git a/src/Device/Sampler.hpp b/src/Device/Sampler.hpp
index f86db85..0013b8d 100644
--- a/src/Device/Sampler.hpp
+++ b/src/Device/Sampler.hpp
@@ -56,13 +56,13 @@
float4 heightLOD;
float4 depthLOD;
- word4 borderColor4[4];
- float4 borderColorF[4];
- float maxAnisotropy;
+ word4 borderColor4[4]; // FIXME(b/129523279): Part of Vulkan sampler.
+ float4 borderColorF[4]; // FIXME(b/129523279): Part of Vulkan sampler.
+ float maxAnisotropy; // FIXME(b/129523279): Part of Vulkan sampler.
int baseLevel;
int maxLevel;
- float minLod;
- float maxLod;
+ float minLod; // FIXME(b/129523279): Part of Vulkan sampler.
+ float maxLod; // FIXME(b/129523279): Part of Vulkan sampler.
};
enum SamplerType
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index d799252..fd83369 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -227,7 +227,7 @@
return c;
}
- Vector4f SamplerCore::sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
+ Vector4f SamplerCore::sampleTextureF(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function)
{
Vector4f c;
diff --git a/src/Pipeline/SamplerCore.hpp b/src/Pipeline/SamplerCore.hpp
index 684c1a7..0567fcd 100644
--- a/src/Pipeline/SamplerCore.hpp
+++ b/src/Pipeline/SamplerCore.hpp
@@ -51,7 +51,7 @@
SamplerCore(Pointer<Byte> &constants, const Sampler::State &state);
Vector4s sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy);
- Vector4f sampleTexture(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
+ Vector4f sampleTextureF(Pointer<Byte> &texture, Float4 &u, Float4 &v, Float4 &w, Float4 &q, Float4 &bias, Vector4f &dsx, Vector4f &dsy, Vector4f &offset, SamplerFunction function);
static Vector4f textureSize(Pointer<Byte> &mipmap, Float4 &lod);
private:
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 11b91ff..d212ff1 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -14,6 +14,7 @@
#include "SpirvShader.hpp"
+#include "SamplerCore.hpp"
#include "System/Math.hpp"
#include "Vulkan/VkBuffer.hpp"
#include "Vulkan/VkDebug.hpp"
@@ -27,6 +28,7 @@
#ifdef Bool
#undef Bool // b/127920555
+#undef None
#endif
namespace
@@ -338,6 +340,12 @@
break; // Correctly handled.
case spv::StorageClassUniformConstant:
+ // This storage class is for data stored within the descriptor itself,
+ // unlike StorageClassUniform which contains handles to buffers.
+ // For Vulkan it corresponds with samplers, images, or combined image samplers.
+ object.kind = Object::Kind::SampledImage;
+ break;
+
case spv::StorageClassWorkgroup:
case spv::StorageClassCrossWorkgroup:
case spv::StorageClassGeneric:
@@ -470,9 +478,12 @@
break;
case spv::OpFConvert:
+ UNIMPLEMENTED("No valid uses for OpFConvert until we support multiple bit widths enabled by features such as Float16/Float64 etc.");
+ break;
+
case spv::OpSConvert:
case spv::OpUConvert:
- UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
+ UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths enabled by features such as Int16/Int64 etc.");
break;
case spv::OpLoad:
@@ -597,18 +608,10 @@
case spv::OpFwidthFine:
case spv::OpAtomicLoad:
case spv::OpPhi:
- // Instructions that yield an intermediate value or divergent
- // pointer
- {
- Type::ID typeId = insn.word(1);
- Object::ID resultId = insn.word(2);
- auto &object = defs[resultId];
- object.type = typeId;
- object.kind = (getType(typeId).opcode() == spv::OpTypePointer)
- ? Object::Kind::DivergentPointer : Object::Kind::Intermediate;
- object.definition = insn;
+ case spv::OpImageSampleImplicitLod:
+ // Instructions that yield an intermediate value or divergent pointer
+ DefineResult(insn);
break;
- }
case spv::OpStore:
case spv::OpAtomicStore:
@@ -1852,6 +1855,8 @@
case spv::OpTypeStruct:
case spv::OpTypePointer:
case spv::OpTypeFunction:
+ case spv::OpTypeImage:
+ case spv::OpTypeSampledImage:
case spv::OpExecutionMode:
case spv::OpMemoryModel:
case spv::OpFunction:
@@ -2056,6 +2061,9 @@
case spv::OpKill:
return EmitKill(insn, state);
+ case spv::OpImageSampleImplicitLod:
+ return EmitImageSampleImplicitLod(insn, state);
+
default:
UNIMPLEMENTED("opcode: %s", OpcodeName(opcode).c_str());
break;
@@ -2095,6 +2103,20 @@
routine->createPointer(resultId, &routine->getVariable(resultId)[0]);
break;
}
+ case spv::StorageClassUniformConstant:
+ {
+ const auto &d = descriptorDecorations.at(resultId);
+ ASSERT(d.DescriptorSet >= 0);
+ ASSERT(d.Binding >= 0);
+
+ uint32_t arrayIndex = 0; // TODO(b/129523279)
+ auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
+ size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
+ Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
+ Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // SampledImageDescriptor*
+ routine->createPointer(resultId, binding);
+ break;
+ }
case spv::StorageClassUniform:
case spv::StorageClassStorageBuffer:
{
@@ -2133,6 +2155,16 @@
ASSERT(Type::ID(insn.word(1)) == result.type);
ASSERT(!atomic || getType(getType(pointer.type).element).opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer."
+ if(pointer.kind == Object::Kind::SampledImage)
+ {
+ // Just propagate the pointer.
+ // TODO(b/129523279)
+ auto &ptr = routine->getPointer(pointerId);
+ routine->createPointer(resultId, ptr);
+
+ return EmitResult::Continue;
+ }
+
if(atomic)
{
Object::ID semanticsId = insn.word(5);
@@ -4125,6 +4157,86 @@
return EmitResult::Continue;
}
+ SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const
+ {
+ Type::ID resultTypeId = insn.word(1);
+ Object::ID resultId = insn.word(2);
+ Object::ID sampledImageId = insn.word(3);
+ Object::ID coordinateId = insn.word(4);
+ auto &resultType = getType(resultTypeId);
+
+ auto &result = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
+ auto &sampledImage = state->routine->getPointer(sampledImageId);
+ auto coordinate = GenericValue(this, state->routine, coordinateId);
+
+ Pointer<Byte> constants; // FIXME(b/129523279)
+
+ const DescriptorDecorations &d = descriptorDecorations.at(sampledImageId);
+ uint32_t arrayIndex = 0; // TODO(b/129523279)
+ auto setLayout = state->routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
+ size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
+
+ const uint8_t *p = reinterpret_cast<const uint8_t*>(state->descriptorSets[d.DescriptorSet]) + bindingOffset;
+ const auto *t = reinterpret_cast<const vk::SampledImageDescriptor*>(p);
+
+ Sampler::State samplerState;
+ samplerState.textureType = TEXTURE_2D; ASSERT(t->imageView->getType() == VK_IMAGE_VIEW_TYPE_2D); // TODO(b/129523279)
+ samplerState.textureFormat = t->imageView->getFormat();
+ samplerState.textureFilter = FILTER_POINT; ASSERT(t->sampler->magFilter == VK_FILTER_NEAREST); ASSERT(t->sampler->minFilter == VK_FILTER_NEAREST); // TODO(b/129523279)
+
+ samplerState.addressingModeU = ADDRESSING_WRAP; ASSERT(t->sampler->addressModeU == VK_SAMPLER_ADDRESS_MODE_REPEAT); // TODO(b/129523279)
+ samplerState.addressingModeV = ADDRESSING_WRAP; ASSERT(t->sampler->addressModeV == VK_SAMPLER_ADDRESS_MODE_REPEAT); // TODO(b/129523279)
+ samplerState.addressingModeW = ADDRESSING_WRAP; ASSERT(t->sampler->addressModeW == VK_SAMPLER_ADDRESS_MODE_REPEAT); // TODO(b/129523279)
+ samplerState.mipmapFilter = MIPMAP_POINT; ASSERT(t->sampler->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST); // TODO(b/129523279)
+ samplerState.sRGB = false; ASSERT(t->imageView->getFormat().isSRGBformat() == false); // TODO(b/129523279)
+ samplerState.swizzleR = SWIZZLE_RED; ASSERT(t->imageView->getComponentMapping().r == VK_COMPONENT_SWIZZLE_R); // TODO(b/129523279)
+ samplerState.swizzleG = SWIZZLE_GREEN; ASSERT(t->imageView->getComponentMapping().g == VK_COMPONENT_SWIZZLE_G); // TODO(b/129523279)
+ samplerState.swizzleB = SWIZZLE_BLUE; ASSERT(t->imageView->getComponentMapping().b == VK_COMPONENT_SWIZZLE_B); // TODO(b/129523279)
+ samplerState.swizzleA = SWIZZLE_ALPHA; ASSERT(t->imageView->getComponentMapping().a == VK_COMPONENT_SWIZZLE_A); // TODO(b/129523279)
+ samplerState.highPrecisionFiltering = false;
+ samplerState.compare = COMPARE_BYPASS; ASSERT(t->sampler->compareEnable == VK_FALSE); // TODO(b/129523279)
+
+ // minLod // TODO(b/129523279)
+ // maxLod // TODO(b/129523279)
+ // borderColor // TODO(b/129523279)
+ ASSERT(t->sampler->mipLodBias == 0.0f); // TODO(b/129523279)
+ ASSERT(t->sampler->anisotropyEnable == VK_FALSE); // TODO(b/129523279)
+ ASSERT(t->sampler->unnormalizedCoordinates == VK_FALSE); // TODO(b/129523279)
+
+ SamplerCore sampler(constants, samplerState);
+
+ Pointer<Byte> texture = sampledImage + OFFSET(vk::SampledImageDescriptor, texture); // sw::Texture*
+ SIMD::Float u = coordinate.Float(0);
+ SIMD::Float v = coordinate.Float(1);
+ SIMD::Float w(0); // TODO(b/129523279)
+ SIMD::Float q(0); // TODO(b/129523279)
+ SIMD::Float bias(0); // TODO(b/129523279)
+ Vector4f dsx; // TODO(b/129523279)
+ Vector4f dsy; // TODO(b/129523279)
+ Vector4f offset; // TODO(b/129523279)
+ SamplerFunction samplerFunction = { Implicit, None }; ASSERT(insn.wordCount() == 5); // TODO(b/129523279)
+
+ Vector4f sample = sampler.sampleTextureF(texture, u, v, w, q, bias, dsx, dsy, offset, samplerFunction);
+
+ if(getType(resultType.element).opcode() == spv::OpTypeFloat)
+ {
+ result.move(0, sample.x);
+ result.move(1, sample.y);
+ result.move(2, sample.z);
+ result.move(3, sample.w);
+ }
+ else
+ {
+ // TODO(b/129523279): Add a Sampler::sampleTextureI() method.
+ result.move(0, As<SIMD::Int>(sample.x * SIMD::Float(0xFF)));
+ result.move(1, As<SIMD::Int>(sample.y * SIMD::Float(0xFF)));
+ result.move(2, As<SIMD::Int>(sample.z * SIMD::Float(0xFF)));
+ result.move(3, As<SIMD::Int>(sample.w * SIMD::Float(0xFF)));
+ }
+
+ return EmitResult::Continue;
+ }
+
void SpirvShader::emitEpilog(SpirvRoutine *routine) const
{
for (auto insn : *this)
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 35120af..16a97cc 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -283,6 +283,9 @@
// A pointer to a vk::DescriptorSet*.
// Pointer held by SpirvRoutine::pointers.
DescriptorSet,
+
+ // Pointer to an image/sampler descriptor.
+ SampledImage,
};
Kind kind = Kind::Unknown;
@@ -719,6 +722,7 @@
EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
+ EmitResult EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const;
// OpcodeName() returns the name of the opcode op.
// If NDEBUG is defined, then OpcodeName() will only return the numerical code.
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index 1d57347..106e3f2 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -13,7 +13,10 @@
// limitations under the License.
#include "VkDescriptorSetLayout.hpp"
+
#include "VkDescriptorSet.hpp"
+#include "VkSampler.hpp"
+#include "VkImageView.hpp"
#include "System/Types.hpp"
#include <algorithm>
@@ -90,6 +93,7 @@
case VK_DESCRIPTOR_TYPE_SAMPLER:
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ return sizeof(SampledImageDescriptor);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return sizeof(VkDescriptorImageInfo);
@@ -153,8 +157,8 @@
{
for(uint32_t j = 0; j < bindings[i].descriptorCount; j++)
{
- VkDescriptorImageInfo* imageInfo = reinterpret_cast<VkDescriptorImageInfo*>(mem);
- imageInfo->sampler = bindings[i].pImmutableSamplers[j];
+ SampledImageDescriptor* imageSamplerDescriptor = reinterpret_cast<SampledImageDescriptor*>(mem);
+ imageSamplerDescriptor->sampler = vk::Cast(bindings[i].pImmutableSamplers[j]);
mem += typeSize;
}
}
@@ -233,25 +237,25 @@
return &descriptorSet->data[byteOffset];
}
-const uint8_t* DescriptorSetLayout::GetInputData(const VkWriteDescriptorSet& descriptorWrites)
+const uint8_t* DescriptorSetLayout::GetInputData(const VkWriteDescriptorSet& writeDescriptorSet)
{
- switch(descriptorWrites.descriptorType)
+ switch(writeDescriptorSet.descriptorType)
{
case VK_DESCRIPTOR_TYPE_SAMPLER:
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
- return reinterpret_cast<const uint8_t*>(descriptorWrites.pImageInfo);
+ return reinterpret_cast<const uint8_t*>(writeDescriptorSet.pImageInfo);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
- return reinterpret_cast<const uint8_t*>(descriptorWrites.pTexelBufferView);
+ return reinterpret_cast<const uint8_t*>(writeDescriptorSet.pTexelBufferView);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
- return reinterpret_cast<const uint8_t*>(descriptorWrites.pBufferInfo);
+ return reinterpret_cast<const uint8_t*>(writeDescriptorSet.pBufferInfo);
break;
default:
UNIMPLEMENTED("descriptorType");
@@ -259,24 +263,186 @@
}
}
-void DescriptorSetLayout::WriteDescriptorSet(const VkWriteDescriptorSet& descriptorWrites)
+void DescriptorSetLayout::WriteDescriptorSet(const VkWriteDescriptorSet& writeDescriptorSet)
{
- DescriptorSet* dstSet = vk::Cast(descriptorWrites.dstSet);
+ DescriptorSet* dstSet = vk::Cast(writeDescriptorSet.dstSet);
DescriptorSetLayout* dstLayout = dstSet->layout;
ASSERT(dstLayout);
- ASSERT(dstLayout->bindings[dstLayout->getBindingIndex(descriptorWrites.dstBinding)].descriptorType == descriptorWrites.descriptorType);
+ ASSERT(dstLayout->bindings[dstLayout->getBindingIndex(writeDescriptorSet.dstBinding)].descriptorType == writeDescriptorSet.descriptorType);
size_t typeSize = 0;
- uint8_t* memToWrite = dstLayout->getOffsetPointer(dstSet, descriptorWrites.dstBinding, descriptorWrites.dstArrayElement, descriptorWrites.descriptorCount, &typeSize);
+ uint8_t* memToWrite = dstLayout->getOffsetPointer(dstSet, writeDescriptorSet.dstBinding, writeDescriptorSet.dstArrayElement, writeDescriptorSet.descriptorCount, &typeSize);
- // If the dstBinding has fewer than descriptorCount array elements remaining
- // starting from dstArrayElement, then the remainder will be used to update
- // the subsequent binding - dstBinding+1 starting at array element zero. If
- // a binding has a descriptorCount of zero, it is skipped. This behavior
- // applies recursively, with the update affecting consecutive bindings as
- // needed to update all descriptorCount descriptors.
- size_t writeSize = typeSize * descriptorWrites.descriptorCount;
- memcpy(memToWrite, DescriptorSetLayout::GetInputData(descriptorWrites), writeSize);
+ if(writeDescriptorSet.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
+ {
+ SampledImageDescriptor *imageSampler = reinterpret_cast<SampledImageDescriptor*>(memToWrite);
+
+ for(uint32_t i = 0; i < writeDescriptorSet.descriptorCount; i++)
+ {
+ vk::Sampler *sampler = vk::Cast(writeDescriptorSet.pImageInfo[i].sampler);
+ vk::ImageView *imageView = vk::Cast(writeDescriptorSet.pImageInfo[i].imageView);
+
+ imageSampler[i].sampler = sampler;
+ imageSampler[i].imageView = imageView;
+
+ sw::Texture *texture = &imageSampler[i].texture;
+ memset(texture, 0, sizeof(sw::Texture)); // TODO(b/129523279): eliminate
+
+ auto &subresourceRange = imageView->getSubresourceRange();
+ int baseLevel = subresourceRange.baseMipLevel;
+
+ for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++)
+ {
+ int level = mipmapLevel - baseLevel; // Level within the image view
+ level = sw::clamp(level, 0, (int)subresourceRange.levelCount);
+
+ VkOffset3D offset = {0, 0, 0};
+ VkImageAspectFlagBits aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ void *buffer = imageView->getOffsetPointer(offset, aspect);
+
+ sw::Mipmap &mipmap = texture->mipmap[mipmapLevel];
+ mipmap.buffer[0] = buffer;
+
+ VkExtent3D extent = imageView->getMipLevelExtent(level);
+ Format format = imageView->getFormat();
+ int width = extent.width;
+ int height = extent.height;
+ int depth = extent.depth;
+ int pitchP = imageView->rowPitchBytes(aspect, level) / format.bytes();
+ int sliceP = imageView->slicePitchBytes(aspect, level) / format.bytes();
+
+ float exp2LOD = 1.0f;
+
+ if(mipmapLevel == 0)
+ {
+ texture->widthHeightLOD[0] = width * exp2LOD;
+ texture->widthHeightLOD[1] = width * exp2LOD;
+ texture->widthHeightLOD[2] = height * exp2LOD;
+ texture->widthHeightLOD[3] = height * exp2LOD;
+
+ texture->widthLOD[0] = width * exp2LOD;
+ texture->widthLOD[1] = width * exp2LOD;
+ texture->widthLOD[2] = width * exp2LOD;
+ texture->widthLOD[3] = width * exp2LOD;
+
+ texture->heightLOD[0] = height * exp2LOD;
+ texture->heightLOD[1] = height * exp2LOD;
+ texture->heightLOD[2] = height * exp2LOD;
+ texture->heightLOD[3] = height * exp2LOD;
+
+ texture->depthLOD[0] = depth * exp2LOD;
+ texture->depthLOD[1] = depth * exp2LOD;
+ texture->depthLOD[2] = depth * exp2LOD;
+ texture->depthLOD[3] = depth * exp2LOD;
+ }
+
+ if(format.isFloatFormat())
+ {
+ mipmap.fWidth[0] = (float)width / 65536.0f;
+ mipmap.fWidth[1] = (float)width / 65536.0f;
+ mipmap.fWidth[2] = (float)width / 65536.0f;
+ mipmap.fWidth[3] = (float)width / 65536.0f;
+
+ mipmap.fHeight[0] = (float)height / 65536.0f;
+ mipmap.fHeight[1] = (float)height / 65536.0f;
+ mipmap.fHeight[2] = (float)height / 65536.0f;
+ mipmap.fHeight[3] = (float)height / 65536.0f;
+
+ mipmap.fDepth[0] = (float)depth / 65536.0f;
+ mipmap.fDepth[1] = (float)depth / 65536.0f;
+ mipmap.fDepth[2] = (float)depth / 65536.0f;
+ mipmap.fDepth[3] = (float)depth / 65536.0f;
+ }
+
+ short halfTexelU = 0x8000 / width;
+ short halfTexelV = 0x8000 / height;
+ short halfTexelW = 0x8000 / depth;
+
+ mipmap.uHalf[0] = halfTexelU;
+ mipmap.uHalf[1] = halfTexelU;
+ mipmap.uHalf[2] = halfTexelU;
+ mipmap.uHalf[3] = halfTexelU;
+
+ mipmap.vHalf[0] = halfTexelV;
+ mipmap.vHalf[1] = halfTexelV;
+ mipmap.vHalf[2] = halfTexelV;
+ mipmap.vHalf[3] = halfTexelV;
+
+ mipmap.wHalf[0] = halfTexelW;
+ mipmap.wHalf[1] = halfTexelW;
+ mipmap.wHalf[2] = halfTexelW;
+ mipmap.wHalf[3] = halfTexelW;
+
+ mipmap.width[0] = width;
+ mipmap.width[1] = width;
+ mipmap.width[2] = width;
+ mipmap.width[3] = width;
+
+ mipmap.height[0] = height;
+ mipmap.height[1] = height;
+ mipmap.height[2] = height;
+ mipmap.height[3] = height;
+
+ mipmap.depth[0] = depth;
+ mipmap.depth[1] = depth;
+ mipmap.depth[2] = depth;
+ mipmap.depth[3] = depth;
+
+ mipmap.onePitchP[0] = 1;
+ mipmap.onePitchP[1] = pitchP;
+ mipmap.onePitchP[2] = 1;
+ mipmap.onePitchP[3] = pitchP;
+
+ mipmap.pitchP[0] = pitchP;
+ mipmap.pitchP[1] = pitchP;
+ mipmap.pitchP[2] = pitchP;
+ mipmap.pitchP[3] = pitchP;
+
+ mipmap.sliceP[0] = sliceP;
+ mipmap.sliceP[1] = sliceP;
+ mipmap.sliceP[2] = sliceP;
+ mipmap.sliceP[3] = sliceP;
+
+ // TODO(b/129523279)
+ if(false/*format == FORMAT_YV12_BT601 ||
+ format == FORMAT_YV12_BT709 ||
+ format == FORMAT_YV12_JFIF*/)
+ {
+ unsigned int YStride = pitchP;
+ unsigned int YSize = YStride * height;
+ unsigned int CStride = sw::align<16>(YStride / 2);
+ unsigned int CSize = CStride * height / 2;
+
+ mipmap.buffer[1] = (sw::byte*)mipmap.buffer[0] + YSize;
+ mipmap.buffer[2] = (sw::byte*)mipmap.buffer[1] + CSize;
+
+ texture->mipmap[1].width[0] = width / 2;
+ texture->mipmap[1].width[1] = width / 2;
+ texture->mipmap[1].width[2] = width / 2;
+ texture->mipmap[1].width[3] = width / 2;
+ texture->mipmap[1].height[0] = height / 2;
+ texture->mipmap[1].height[1] = height / 2;
+ texture->mipmap[1].height[2] = height / 2;
+ texture->mipmap[1].height[3] = height / 2;
+ texture->mipmap[1].onePitchP[0] = 1;
+ texture->mipmap[1].onePitchP[1] = CStride;
+ texture->mipmap[1].onePitchP[2] = 1;
+ texture->mipmap[1].onePitchP[3] = CStride;
+ }
+ }
+ }
+ }
+ else
+ {
+ // If the dstBinding has fewer than descriptorCount array elements remaining
+ // starting from dstArrayElement, then the remainder will be used to update
+ // the subsequent binding - dstBinding+1 starting at array element zero. If
+ // a binding has a descriptorCount of zero, it is skipped. This behavior
+ // applies recursively, with the update affecting consecutive bindings as
+ // needed to update all descriptorCount descriptors.
+ size_t writeSize = typeSize * writeDescriptorSet.descriptorCount;
+ memcpy(memToWrite, DescriptorSetLayout::GetInputData(writeDescriptorSet), writeSize);
+ }
}
void DescriptorSetLayout::CopyDescriptorSet(const VkCopyDescriptorSet& descriptorCopies)
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index d5aa560..6ccd12e 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -17,11 +17,25 @@
#include "VkObject.hpp"
+#include "Vulkan/VkSampler.hpp"
+#include "Vulkan/VkImageView.hpp"
+#include "Device/Sampler.hpp"
+
namespace vk
{
class DescriptorSet;
+// TODO(b/129523279): Move to the Device or Pipeline layer.
+struct SampledImageDescriptor
+{
+ // TODO(b/129523279): Minimize to the data actually needed.
+ vk::Sampler *sampler;
+ vk::ImageView *imageView;
+
+ sw::Texture texture;
+};
+
class DescriptorSetLayout : public Object<DescriptorSetLayout, VkDescriptorSetLayout>
{
public:
diff --git a/src/Vulkan/VkFormat.cpp b/src/Vulkan/VkFormat.cpp
index c201389..d3a48c7 100644
--- a/src/Vulkan/VkFormat.cpp
+++ b/src/Vulkan/VkFormat.cpp
@@ -144,7 +144,6 @@
bool Format::isSRGBreadable() const
{
- // Keep in sync with Capabilities::isSRGBreadable
switch(format)
{
case VK_FORMAT_B8G8R8A8_UNORM:
@@ -160,7 +159,6 @@
bool Format::isSRGBwritable() const
{
- // Keep in sync with Capabilities::isSRGBwritable
switch(format)
{
case VK_FORMAT_UNDEFINED:
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp
index 5466d1e..4e54f8a 100644
--- a/src/Vulkan/VkImageView.hpp
+++ b/src/Vulkan/VkImageView.hpp
@@ -36,23 +36,28 @@
void clear(const VkClearValue& clearValue, VkImageAspectFlags aspectMask, const VkClearRect& renderArea);
void resolve(ImageView* resolveAttachment);
+ VkImageViewType getType() const { return viewType; }
Format getFormat() const { return format; }
int getSampleCount() const { return image->getSampleCountFlagBits(); }
- int rowPitchBytes(VkImageAspectFlagBits aspect) const { return image->rowPitchBytes(aspect, subresourceRange.baseMipLevel); }
- int slicePitchBytes(VkImageAspectFlagBits aspect) const { return image->slicePitchBytes(aspect, subresourceRange.baseMipLevel); }
+ int rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const { return image->rowPitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel); }
+ int slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const { return image->slicePitchBytes(aspect, subresourceRange.baseMipLevel + mipLevel); }
+ VkExtent3D getMipLevelExtent(uint32_t mipLevel) const { return image->getMipLevelExtent(subresourceRange.baseMipLevel + mipLevel); }
void *getOffsetPointer(const VkOffset3D& offset, VkImageAspectFlagBits aspect) 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; }
-private:
- bool imageTypesMatch(VkImageType imageType) const;
+ const VkComponentMapping &getComponentMapping() const { return components; }
+ const VkImageSubresourceRange &getSubresourceRange() const { return subresourceRange; }
- Image* image = nullptr;
- VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
- Format format;
- VkComponentMapping components = {};
- VkImageSubresourceRange subresourceRange = {};
+private:
+ bool imageTypesMatch(VkImageType imageType) const;
+
+ Image *const image = nullptr;
+ const VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
+ const Format format;
+ const VkComponentMapping components = {};
+ const VkImageSubresourceRange subresourceRange = {};
};
static inline ImageView* Cast(VkImageView object)
diff --git a/src/Vulkan/VkSampler.hpp b/src/Vulkan/VkSampler.hpp
index fc62389..5fa0b4e 100644
--- a/src/Vulkan/VkSampler.hpp
+++ b/src/Vulkan/VkSampler.hpp
@@ -49,22 +49,21 @@
return 0;
}
-private:
- VkFilter magFilter = VK_FILTER_NEAREST;
- VkFilter minFilter = VK_FILTER_NEAREST;
- VkSamplerMipmapMode mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
- VkSamplerAddressMode addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- VkSamplerAddressMode addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- VkSamplerAddressMode addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- float mipLodBias = 0.0f;
- VkBool32 anisotropyEnable = VK_FALSE;
- float maxAnisotropy = 0.0f;
- VkBool32 compareEnable = VK_FALSE;
- VkCompareOp compareOp = VK_COMPARE_OP_NEVER;
- float minLod = 0.0f;
- float maxLod = 0.0f;
- VkBorderColor borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
- VkBool32 unnormalizedCoordinates = VK_FALSE;
+ const VkFilter magFilter = VK_FILTER_NEAREST;
+ const VkFilter minFilter = VK_FILTER_NEAREST;
+ const VkSamplerMipmapMode mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
+ const VkSamplerAddressMode addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ const VkSamplerAddressMode addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ const VkSamplerAddressMode addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+ const float mipLodBias = 0.0f;
+ const VkBool32 anisotropyEnable = VK_FALSE;
+ const float maxAnisotropy = 0.0f;
+ const VkBool32 compareEnable = VK_FALSE;
+ const VkCompareOp compareOp = VK_COMPARE_OP_NEVER;
+ const float minLod = 0.0f;
+ const float maxLod = 0.0f;
+ const VkBorderColor borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ const VkBool32 unnormalizedCoordinates = VK_FALSE;
};
static inline Sampler* Cast(VkSampler object)