Commit 125dba0b by Nicolas Capens Committed by Nicolas Capens

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/+/29774Tested-by: 's avatarNicolas Capens <nicolascapens@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarChris Forbes <chrisforbes@google.com>
parent a94ca189
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#define sw_PixelProgram_hpp #define sw_PixelProgram_hpp
#include "PixelRoutine.hpp" #include "PixelRoutine.hpp"
#include "SamplerCore.hpp"
namespace sw namespace sw
{ {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "SamplerCore.hpp" #include "SamplerCore.hpp"
#include "PixelRoutine.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Vulkan/VkDebug.hpp" #include "Vulkan/VkDebug.hpp"
......
...@@ -15,11 +15,18 @@ ...@@ -15,11 +15,18 @@
#ifndef sw_SamplerCore_hpp #ifndef sw_SamplerCore_hpp
#define sw_SamplerCore_hpp #define sw_SamplerCore_hpp
#include "PixelRoutine.hpp" #include "ShaderCore.hpp"
#include "Device/Sampler.hpp"
#include "Reactor/Reactor.hpp" #include "Reactor/Reactor.hpp"
#ifdef None
#undef None // b/127920555
#endif
namespace sw namespace sw
{ {
using namespace rr;
enum SamplerMethod enum SamplerMethod
{ {
Implicit, // Compute gradients (pixel shader only). Implicit, // Compute gradients (pixel shader only).
......
...@@ -333,7 +333,9 @@ namespace sw ...@@ -333,7 +333,9 @@ namespace sw
for (auto insn : *this) for (auto insn : *this)
{ {
switch (insn.opcode()) spv::Op opcode = insn.opcode();
switch (opcode)
{ {
case spv::OpExecutionMode: case spv::OpExecutionMode:
ProcessExecutionMode(insn); ProcessExecutionMode(insn);
...@@ -444,7 +446,7 @@ namespace sw ...@@ -444,7 +446,7 @@ namespace sw
blocks[currentBlock] = Block(blockStart, blockEnd); blocks[currentBlock] = Block(blockStart, blockEnd);
currentBlock = Block::ID(0); currentBlock = Block::ID(0);
if (insn.opcode() == spv::OpKill) if (opcode == spv::OpKill)
{ {
modes.ContainsKill = true; modes.ContainsKill = true;
} }
...@@ -639,7 +641,7 @@ namespace sw ...@@ -639,7 +641,7 @@ namespace sw
case spv::OpSpecConstantTrue: case spv::OpSpecConstantTrue:
// These should have all been removed by preprocessing passes. If we see them here, // 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. // 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; break;
case spv::OpFConvert: case spv::OpFConvert:
...@@ -667,7 +669,7 @@ namespace sw ...@@ -667,7 +669,7 @@ namespace sw
DefineResult(insn); DefineResult(insn);
if (insn.opcode() == spv::OpAccessChain || insn.opcode() == spv::OpInBoundsAccessChain) if (opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain)
{ {
Decorations dd{}; Decorations dd{};
ApplyDecorationsForAccessChain(&dd, pointerId, insn.wordCount() - 4, insn.wordPointer(4)); ApplyDecorationsForAccessChain(&dd, pointerId, insn.wordCount() - 4, insn.wordPointer(4));
...@@ -787,6 +789,7 @@ namespace sw ...@@ -787,6 +789,7 @@ namespace sw
case spv::OpAtomicCompareExchange: case spv::OpAtomicCompareExchange:
case spv::OpPhi: case spv::OpPhi:
case spv::OpImageSampleImplicitLod: case spv::OpImageSampleImplicitLod:
case spv::OpImageSampleExplicitLod:
case spv::OpImageQuerySize: case spv::OpImageQuerySize:
case spv::OpImageRead: case spv::OpImageRead:
case spv::OpImageTexelPointer: case spv::OpImageTexelPointer:
...@@ -811,7 +814,7 @@ namespace sw ...@@ -811,7 +814,7 @@ namespace sw
} }
default: default:
UNIMPLEMENTED("%s", OpcodeName(insn.opcode()).c_str()); UNIMPLEMENTED("%s", OpcodeName(opcode).c_str());
} }
} }
...@@ -2316,6 +2319,9 @@ namespace sw ...@@ -2316,6 +2319,9 @@ namespace sw
case spv::OpImageSampleImplicitLod: case spv::OpImageSampleImplicitLod:
return EmitImageSampleImplicitLod(insn, state); return EmitImageSampleImplicitLod(insn, state);
case spv::OpImageSampleExplicitLod:
return EmitImageSampleExplicitLod(insn, state);
case spv::OpImageQuerySize: case spv::OpImageQuerySize:
return EmitImageQuerySize(insn, state); return EmitImageQuerySize(insn, state);
...@@ -4364,6 +4370,16 @@ namespace sw ...@@ -4364,6 +4370,16 @@ namespace sw
SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const 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); Type::ID resultTypeId = insn.word(1);
Object::ID resultId = insn.word(2); Object::ID resultId = insn.word(2);
Object::ID sampledImageId = insn.word(3); Object::ID sampledImageId = insn.word(3);
...@@ -4373,6 +4389,7 @@ namespace sw ...@@ -4373,6 +4389,7 @@ namespace sw
auto &result = state->routine->createIntermediate(resultId, resultType.sizeInComponents); auto &result = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
auto &sampledImage = state->routine->getPointer(sampledImageId); auto &sampledImage = state->routine->getPointer(sampledImageId);
auto coordinate = GenericValue(this, state->routine, coordinateId); auto coordinate = GenericValue(this, state->routine, coordinateId);
auto &coordinateType = getType(coordinate.type);
Pointer<Byte> constants; // FIXME(b/129523279) Pointer<Byte> constants; // FIXME(b/129523279)
...@@ -4382,9 +4399,75 @@ namespace sw ...@@ -4382,9 +4399,75 @@ namespace sw
auto samplerFunc = Call(getImageSampler, imageView, sampler); auto samplerFunc = Call(getImageSampler, imageView, sampler);
Array<SIMD::Float> in(2); uint32_t imageOperands = spv::ImageOperandsMaskNone;
in[0] = coordinate.Float(0); bool bias = false;
in[1] = coordinate.Float(1); 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); Array<SIMD::Float> out(4);
Call<ImageSampler>(samplerFunc, sampledImage.base, &in[0], &out[0]); Call<ImageSampler>(samplerFunc, sampledImage.base, &in[0], &out[0]);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define sw_SpirvShader_hpp #define sw_SpirvShader_hpp
#include "ShaderCore.hpp" #include "ShaderCore.hpp"
#include "SamplerCore.hpp"
#include "SpirvID.hpp" #include "SpirvID.hpp"
#include "System/Types.hpp" #include "System/Types.hpp"
#include "Vulkan/VkDebug.hpp" #include "Vulkan/VkDebug.hpp"
...@@ -256,6 +257,9 @@ namespace sw ...@@ -256,6 +257,9 @@ namespace sw
using InsnStore = std::vector<uint32_t>; using InsnStore = std::vector<uint32_t>;
InsnStore insns; 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. */ /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
class InsnIterator class InsnIterator
{ {
...@@ -827,6 +831,8 @@ namespace sw ...@@ -827,6 +831,8 @@ namespace sw
EmitResult EmitKill(InsnIterator insn, EmitState *state) const; EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
EmitResult EmitPhi(InsnIterator insn, EmitState *state) const; EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageSampleImplicitLod(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 EmitImageQuerySize(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const; EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const; EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
...@@ -853,10 +859,11 @@ namespace sw ...@@ -853,10 +859,11 @@ namespace sw
// Returns the pair <significand, exponent> // Returns the pair <significand, exponent>
std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const; std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const;
using ImageSampler = void(void* image, void* uvsIn, void* texelOut); 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(const vk::ImageView *imageView, const vk::Sampler *sampler); static ImageSampler *getImageSampler(SamplerMethod samplerMethod, const vk::ImageView *imageView, const vk::Sampler *sampler);
static void emitSamplerFunction( static void emitSamplerFunction(
SamplerMethod samplerMethod,
const vk::ImageView *imageView, const vk::Sampler *sampler, const vk::ImageView *imageView, const vk::Sampler *sampler,
Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out); Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out);
......
...@@ -39,14 +39,23 @@ ...@@ -39,14 +39,23 @@
namespace sw { 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::unordered_map<uintptr_t, ImageSampler*> cache;
static std::mutex mutex; static std::mutex mutex;
// TODO: Don't use pointers they can be deleted and reused, combine some two // FIXME(b/129523279): Don't use pointers: they can be deleted and reused. Instead combine some two unique ids.
// 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); auto key = reinterpret_cast<uintptr_t>(imageView) ^ reinterpret_cast<uintptr_t>(sampler);
std::unique_lock<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
...@@ -58,13 +67,14 @@ SpirvShader::ImageSampler *SpirvShader::getImageSampler(const vk::ImageView *ima ...@@ -58,13 +67,14 @@ SpirvShader::ImageSampler *SpirvShader::getImageSampler(const vk::ImageView *ima
Pointer<Byte> image = function.Arg<0>(); Pointer<Byte> image = function.Arg<0>();
Pointer<SIMD::Float> in = function.Arg<1>(); Pointer<SIMD::Float> in = function.Arg<1>();
Pointer<SIMD::Float> out = function.Arg<2>(); 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()); auto fptr = reinterpret_cast<ImageSampler*>((void *)function("sampler")->getEntry());
cache.emplace(key, fptr); cache.emplace(key, fptr);
return fptr; return fptr;
} }
void SpirvShader::emitSamplerFunction( void SpirvShader::emitSamplerFunction(
SamplerMethod samplerMethod,
const vk::ImageView *imageView, const vk::Sampler *sampler, const vk::ImageView *imageView, const vk::Sampler *sampler,
Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out) Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out)
{ {
...@@ -102,11 +112,16 @@ void SpirvShader::emitSamplerFunction( ...@@ -102,11 +112,16 @@ void SpirvShader::emitSamplerFunction(
Pointer<Byte> texture = image + OFFSET(vk::SampledImageDescriptor, texture); // sw::Texture* Pointer<Byte> texture = image + OFFSET(vk::SampledImageDescriptor, texture); // sw::Texture*
SIMD::Float w(0); // TODO(b/129523279) SIMD::Float w(0); // TODO(b/129523279)
SIMD::Float q(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 dsx; // TODO(b/129523279)
Vector4f dsy; // TODO(b/129523279) Vector4f dsy; // TODO(b/129523279)
Vector4f offset; // 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); Vector4f sample = s.sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, samplerFunction);
......
...@@ -18,10 +18,6 @@ ...@@ -18,10 +18,6 @@
#include "VertexRoutine.hpp" #include "VertexRoutine.hpp"
#include "ShaderCore.hpp" #include "ShaderCore.hpp"
#include "SamplerCore.hpp"
#include "Device/Stream.hpp"
#include "System/Types.hpp"
namespace sw namespace sw
{ {
struct Stream; struct Stream;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment