Implement OpImageSampleExplicitLod
Emit a call to a different trampoline function for generating the
sampler code, which unifies the implementation with
OpImageSampleExplicitLod's by using a common EmitImageSample which
takes a sampler 'method' enum. This is then passed at shader execution
time to emitSamplerFunction.
The lod parameter is parsed from the instruction stream in
EmitImageSample. Other (optional) image operands are left unimplemented
for now.
Bug: b/129523279
Test: dEQP-VK.binding_model.shader_access.primary_cmd_buf.combined_image_sampler_mutable.fragment.single_descriptor.2d
Change-Id: I265b81d953fe5a0496d029704a0f5eeff4229823
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29774
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/PixelProgram.hpp b/src/Pipeline/PixelProgram.hpp
index 98fa19d..9f6d14f 100644
--- a/src/Pipeline/PixelProgram.hpp
+++ b/src/Pipeline/PixelProgram.hpp
@@ -16,7 +16,6 @@
#define sw_PixelProgram_hpp
#include "PixelRoutine.hpp"
-#include "SamplerCore.hpp"
namespace sw
{
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index 1cf08a5..4e39f9e 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -14,6 +14,7 @@
#include "SamplerCore.hpp"
+#include "PixelRoutine.hpp"
#include "Constants.hpp"
#include "Vulkan/VkDebug.hpp"
diff --git a/src/Pipeline/SamplerCore.hpp b/src/Pipeline/SamplerCore.hpp
index 969a117..e6fe4ed 100644
--- a/src/Pipeline/SamplerCore.hpp
+++ b/src/Pipeline/SamplerCore.hpp
@@ -15,11 +15,18 @@
#ifndef sw_SamplerCore_hpp
#define sw_SamplerCore_hpp
-#include "PixelRoutine.hpp"
+#include "ShaderCore.hpp"
+#include "Device/Sampler.hpp"
#include "Reactor/Reactor.hpp"
+#ifdef None
+#undef None // b/127920555
+#endif
+
namespace sw
{
+ using namespace rr;
+
enum SamplerMethod
{
Implicit, // Compute gradients (pixel shader only).
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index db30143..7d3df93 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -333,7 +333,9 @@
for (auto insn : *this)
{
- switch (insn.opcode())
+ spv::Op opcode = insn.opcode();
+
+ switch (opcode)
{
case spv::OpExecutionMode:
ProcessExecutionMode(insn);
@@ -444,7 +446,7 @@
blocks[currentBlock] = Block(blockStart, blockEnd);
currentBlock = Block::ID(0);
- if (insn.opcode() == spv::OpKill)
+ if (opcode == spv::OpKill)
{
modes.ContainsKill = true;
}
@@ -639,7 +641,7 @@
case spv::OpSpecConstantTrue:
// These should have all been removed by preprocessing passes. If we see them here,
// our assumptions are wrong and we will probably generate wrong code.
- UNIMPLEMENTED("%s should have already been lowered.", OpcodeName(insn.opcode()).c_str());
+ UNIMPLEMENTED("%s should have already been lowered.", OpcodeName(opcode).c_str());
break;
case spv::OpFConvert:
@@ -667,7 +669,7 @@
DefineResult(insn);
- if (insn.opcode() == spv::OpAccessChain || insn.opcode() == spv::OpInBoundsAccessChain)
+ if (opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain)
{
Decorations dd{};
ApplyDecorationsForAccessChain(&dd, pointerId, insn.wordCount() - 4, insn.wordPointer(4));
@@ -787,6 +789,7 @@
case spv::OpAtomicCompareExchange:
case spv::OpPhi:
case spv::OpImageSampleImplicitLod:
+ case spv::OpImageSampleExplicitLod:
case spv::OpImageQuerySize:
case spv::OpImageRead:
case spv::OpImageTexelPointer:
@@ -811,7 +814,7 @@
}
default:
- UNIMPLEMENTED("%s", OpcodeName(insn.opcode()).c_str());
+ UNIMPLEMENTED("%s", OpcodeName(opcode).c_str());
}
}
@@ -2316,6 +2319,9 @@
case spv::OpImageSampleImplicitLod:
return EmitImageSampleImplicitLod(insn, state);
+ case spv::OpImageSampleExplicitLod:
+ return EmitImageSampleExplicitLod(insn, state);
+
case spv::OpImageQuerySize:
return EmitImageQuerySize(insn, state);
@@ -4364,6 +4370,16 @@
SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const
{
+ return EmitImageSample(getImageSamplerImplicitLod, insn, state);
+ }
+
+ SpirvShader::EmitResult SpirvShader::EmitImageSampleExplicitLod(InsnIterator insn, EmitState *state) const
+ {
+ return EmitImageSample(getImageSamplerExplicitLod, insn, state);
+ }
+
+ SpirvShader::EmitResult SpirvShader::EmitImageSample(GetImageSampler getImageSampler, InsnIterator insn, EmitState *state) const
+ {
Type::ID resultTypeId = insn.word(1);
Object::ID resultId = insn.word(2);
Object::ID sampledImageId = insn.word(3);
@@ -4373,6 +4389,7 @@
auto &result = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
auto &sampledImage = state->routine->getPointer(sampledImageId);
auto coordinate = GenericValue(this, state->routine, coordinateId);
+ auto &coordinateType = getType(coordinate.type);
Pointer<Byte> constants; // FIXME(b/129523279)
@@ -4382,9 +4399,75 @@
auto samplerFunc = Call(getImageSampler, imageView, sampler);
- Array<SIMD::Float> in(2);
- in[0] = coordinate.Float(0);
- in[1] = coordinate.Float(1);
+ uint32_t imageOperands = spv::ImageOperandsMaskNone;
+ bool bias = false;
+ bool lod = false;
+ Object::ID lodId = 0;
+ bool grad = false;
+ bool constOffset = false;
+ bool sample = false;
+
+ if(insn.wordCount() > 5)
+ {
+ imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(5));
+ uint32_t operand = 6;
+
+ if(imageOperands & spv::ImageOperandsBiasMask)
+ {
+ UNIMPLEMENTED("Image operand %x", spv::ImageOperandsBiasMask); (void)bias;
+ bias = true;
+ imageOperands &= ~spv::ImageOperandsBiasMask;
+ }
+
+ if(imageOperands & spv::ImageOperandsLodMask)
+ {
+ lod = true;
+ lodId = insn.word(operand);
+ operand++;
+ imageOperands &= ~spv::ImageOperandsLodMask;
+ }
+
+ if(imageOperands & spv::ImageOperandsGradMask)
+ {
+ UNIMPLEMENTED("Image operand %x", spv::ImageOperandsGradMask); (void)grad;
+ grad = true;
+ imageOperands &= ~spv::ImageOperandsGradMask;
+ }
+
+ if(imageOperands & spv::ImageOperandsConstOffsetMask)
+ {
+ UNIMPLEMENTED("Image operand %x", spv::ImageOperandsConstOffsetMask); (void)constOffset;
+ constOffset = true;
+ imageOperands &= ~spv::ImageOperandsConstOffsetMask;
+ }
+
+ if(imageOperands & spv::ImageOperandsSampleMask)
+ {
+ UNIMPLEMENTED("Image operand %x", spv::ImageOperandsSampleMask); (void)sample;
+ sample = true;
+ imageOperands &= ~spv::ImageOperandsSampleMask;
+ }
+
+ if(imageOperands != 0)
+ {
+ UNIMPLEMENTED("Image operand %x", imageOperands);
+ }
+ }
+
+ Array<SIMD::Float> in(coordinateType.sizeInComponents + lod);
+
+ uint32_t i = 0;
+ for( ; i < coordinateType.sizeInComponents; i++)
+ {
+ in[i] = coordinate.Float(i);
+ }
+
+ if(lod)
+ {
+ auto lodValue = GenericValue(this, state->routine, lodId);
+ in[i] = lodValue.Float(0);
+ i++;
+ }
Array<SIMD::Float> out(4);
Call<ImageSampler>(samplerFunc, sampledImage.base, &in[0], &out[0]);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 0d5c154..d11cbce 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -16,6 +16,7 @@
#define sw_SpirvShader_hpp
#include "ShaderCore.hpp"
+#include "SamplerCore.hpp"
#include "SpirvID.hpp"
#include "System/Types.hpp"
#include "Vulkan/VkDebug.hpp"
@@ -256,6 +257,9 @@
using InsnStore = std::vector<uint32_t>;
InsnStore insns;
+ using ImageSampler = void(void* image, void* uvsIn, void* texelOut);
+ using GetImageSampler = ImageSampler*(const vk::ImageView *imageView, const vk::Sampler *sampler);
+
/* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
class InsnIterator
{
@@ -827,6 +831,8 @@
EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const;
+ EmitResult EmitImageSampleExplicitLod(InsnIterator insn, EmitState *state) const;
+ EmitResult EmitImageSample(GetImageSampler getImageSampler, InsnIterator insn, EmitState *state) const;
EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
@@ -853,10 +859,11 @@
// Returns the pair <significand, exponent>
std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const;
- using ImageSampler = void(void* image, void* uvsIn, void* texelOut);
-
- static ImageSampler *getImageSampler(const vk::ImageView *imageView, const vk::Sampler *sampler);
+ static ImageSampler *getImageSamplerImplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler);
+ static ImageSampler *getImageSamplerExplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler);
+ static ImageSampler *getImageSampler(SamplerMethod samplerMethod, const vk::ImageView *imageView, const vk::Sampler *sampler);
static void emitSamplerFunction(
+ SamplerMethod samplerMethod,
const vk::ImageView *imageView, const vk::Sampler *sampler,
Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out);
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 5921e55..d8bf659 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -39,14 +39,23 @@
namespace sw {
-SpirvShader::ImageSampler *SpirvShader::getImageSampler(const vk::ImageView *imageView, const vk::Sampler *sampler)
+SpirvShader::ImageSampler *SpirvShader::getImageSamplerImplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler)
{
- // TODO: Move somewhere sensible.
+ return getImageSampler(Implicit, imageView, sampler);
+}
+SpirvShader::ImageSampler *SpirvShader::getImageSamplerExplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler)
+{
+ return getImageSampler(Lod, imageView, sampler);
+}
+
+SpirvShader::ImageSampler *SpirvShader::getImageSampler(SamplerMethod samplerMethod, const vk::ImageView *imageView, const vk::Sampler *sampler)
+{
+ // TODO(b/129523279): Move somewhere sensible.
static std::unordered_map<uintptr_t, ImageSampler*> cache;
static std::mutex mutex;
- // TODO: Don't use pointers they can be deleted and reused, combine some two
- // unique ids.
+ // FIXME(b/129523279): Don't use pointers: they can be deleted and reused. Instead combine some two unique ids.
+ // FIXME(b/129523279): Take instruction opcode and optional parameters into acount (SamplerMethod / SamplerOption).
auto key = reinterpret_cast<uintptr_t>(imageView) ^ reinterpret_cast<uintptr_t>(sampler);
std::unique_lock<std::mutex> lock(mutex);
@@ -58,13 +67,14 @@
Pointer<Byte> image = function.Arg<0>();
Pointer<SIMD::Float> in = function.Arg<1>();
Pointer<SIMD::Float> out = function.Arg<2>();
- emitSamplerFunction(imageView, sampler, image, in, out);
+ emitSamplerFunction(samplerMethod, imageView, sampler, image, in, out);
auto fptr = reinterpret_cast<ImageSampler*>((void *)function("sampler")->getEntry());
cache.emplace(key, fptr);
return fptr;
}
void SpirvShader::emitSamplerFunction(
+ SamplerMethod samplerMethod,
const vk::ImageView *imageView, const vk::Sampler *sampler,
Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out)
{
@@ -102,11 +112,16 @@
Pointer<Byte> texture = image + OFFSET(vk::SampledImageDescriptor, texture); // sw::Texture*
SIMD::Float w(0); // TODO(b/129523279)
SIMD::Float q(0); // TODO(b/129523279)
- SIMD::Float bias(0); // TODO(b/129523279)
+ SIMD::Float bias(0);
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)
+ SamplerFunction samplerFunction = { samplerMethod, None }; // TODO(b/129523279)
+
+ if(samplerMethod == Lod)
+ {
+ bias = in[2]; // TODO(b/129523279): Index depends on view dimensions and other optional operands.
+ }
Vector4f sample = s.sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, samplerFunction);
diff --git a/src/Pipeline/VertexProgram.hpp b/src/Pipeline/VertexProgram.hpp
index 2b4657f..31b8b9e 100644
--- a/src/Pipeline/VertexProgram.hpp
+++ b/src/Pipeline/VertexProgram.hpp
@@ -18,10 +18,6 @@
#include "VertexRoutine.hpp"
#include "ShaderCore.hpp"
-#include "SamplerCore.hpp"
-#include "Device/Stream.hpp"
-#include "System/Types.hpp"
-
namespace sw
{
struct Stream;