Dynamic dispatch for image samplers Bug: b/130746922 Change-Id: I35dfcb93c8e902d0be566fad50ae991d5490e853 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29348 Tested-by: Ben Clayton <bclayton@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj index 0216c93..3d2d37a 100644 --- a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj +++ b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
@@ -242,6 +242,7 @@ <ClInclude Include="$(SolutionDir)src\Pipeline\SpirvID.hpp" /> <ClCompile Include="$(SolutionDir)src\Pipeline\SpirvShader.cpp" /> <ClInclude Include="$(SolutionDir)src\Pipeline\SpirvShader.hpp" /> + <ClCompile Include="$(SolutionDir)src\Pipeline\SpirvShaderSampling.cpp" /> <ClCompile Include="$(SolutionDir)src\Pipeline\SpirvShader_dbg.cpp" /> <ClCompile Include="$(SolutionDir)src\Pipeline\VertexProgram.cpp" /> <ClInclude Include="$(SolutionDir)src\Pipeline\VertexProgram.hpp" />
diff --git a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters index 6d4eb0e..bc7a75c 100644 --- a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters +++ b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
@@ -79,6 +79,9 @@ <ClCompile Include="$(SolutionDir)src\Pipeline\SpirvShader_dbg.cpp"> <Filter>src\Pipeline</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)src\Pipeline\SpirvShaderSampling.cpp"> + <Filter>src\Pipeline</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)src\Pipeline\VertexProgram.cpp"> <Filter>src\Pipeline</Filter> </ClCompile>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index c5df163..50de374 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -4301,63 +4301,20 @@ 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); + auto descriptor = state->routine->descriptorSets[d.DescriptorSet] + bindingOffset; // vk::SampledImageDescriptor* + auto sampler = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::SampledImageDescriptor, sampler)); // vk::Sampler* + auto imageView = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::SampledImageDescriptor, imageView)); // vk::ImageView* - 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) + auto samplerFunc = Call(getImageSampler, imageView, sampler); - 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) + Array<SIMD::Float> in(2); + in[0] = coordinate.Float(0); + in[1] = coordinate.Float(1); - // 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) + Array<SIMD::Float> out(4); + Call<ImageSampler>(samplerFunc, sampledImage, &in[0], &out[0]); - 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))); - } + for (int i = 0; i < 4; i++) { result.move(i, out[i]); } return EmitResult::Continue; }
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp index 69dd01e..f8862b6 100644 --- a/src/Pipeline/SpirvShader.hpp +++ b/src/Pipeline/SpirvShader.hpp
@@ -40,6 +40,8 @@ namespace vk { class PipelineLayout; + class ImageView; + class Sampler; } // namespace vk namespace sw @@ -745,6 +747,13 @@ // x = significand * 2^exponent // 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(vk::ImageView *imageView, vk::Sampler *sampler); + static void emitSamplerFunction( + vk::ImageView *imageView, vk::Sampler *sampler, + Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out); }; class SpirvRoutine
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp new file mode 100644 index 0000000..e90aad0 --- /dev/null +++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -0,0 +1,132 @@ +// Copyright 2019 The SwiftShader Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include "SpirvShader.hpp" + +#include "SamplerCore.hpp" // TODO: Figure out what's needed. +#include "System/Math.hpp" +#include "Vulkan/VkBuffer.hpp" +#include "Vulkan/VkDebug.hpp" +#include "Vulkan/VkDescriptorSet.hpp" +#include "Vulkan/VkPipelineLayout.hpp" +#include "Vulkan/VkImageView.hpp" +#include "Vulkan/VkSampler.hpp" +#include "Vulkan/VkDescriptorSetLayout.hpp" +#include "Device/Config.hpp" + +#include <spirv/unified1/spirv.hpp> +#include <spirv/unified1/GLSL.std.450.h> + + +#include <mutex> + +#ifdef Bool +#undef Bool // b/127920555 +#undef None +#endif + +namespace sw { + +SpirvShader::ImageSampler *SpirvShader::getImageSampler(vk::ImageView *imageView, vk::Sampler *sampler) +{ + // TODO: 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. + auto key = reinterpret_cast<uintptr_t>(imageView) ^ reinterpret_cast<uintptr_t>(sampler); + + std::unique_lock<std::mutex> lock(mutex); + auto it = cache.find(key); + if (it != cache.end()) { return it->second; } + + // TODO: Hold a separate mutex lock for the sampler being built. + auto function = rr::Function<Void(Pointer<Byte> image, Pointer<SIMD::Float>, Pointer<SIMD::Float>)>(); + 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); + auto fptr = reinterpret_cast<ImageSampler*>((void *)function("sampler")->getEntry()); + cache.emplace(key, fptr); + return fptr; +} + +void SpirvShader::emitSamplerFunction( + vk::ImageView *imageView, vk::Sampler *sampler, + Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out) +{ + SIMD::Float u = in[0]; + SIMD::Float v = in[1]; + + Pointer<Byte> constants; // FIXME(b/129523279) + + Sampler::State samplerState; + samplerState.textureType = TEXTURE_2D; ASSERT(imageView->getType() == VK_IMAGE_VIEW_TYPE_2D); // TODO(b/129523279) + samplerState.textureFormat = imageView->getFormat(); + samplerState.textureFilter = FILTER_POINT; ASSERT(sampler->magFilter == VK_FILTER_NEAREST); ASSERT(sampler->minFilter == VK_FILTER_NEAREST); // TODO(b/129523279) + + samplerState.addressingModeU = ADDRESSING_WRAP; ASSERT(sampler->addressModeU == VK_SAMPLER_ADDRESS_MODE_REPEAT); // TODO(b/129523279) + samplerState.addressingModeV = ADDRESSING_WRAP; ASSERT(sampler->addressModeV == VK_SAMPLER_ADDRESS_MODE_REPEAT); // TODO(b/129523279) + samplerState.addressingModeW = ADDRESSING_WRAP; ASSERT(sampler->addressModeW == VK_SAMPLER_ADDRESS_MODE_REPEAT); // TODO(b/129523279) + samplerState.mipmapFilter = MIPMAP_POINT; ASSERT(sampler->mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST); // TODO(b/129523279) + samplerState.sRGB = false; ASSERT(imageView->getFormat().isSRGBformat() == false); // TODO(b/129523279) + samplerState.swizzleR = SWIZZLE_RED; ASSERT(imageView->getComponentMapping().r == VK_COMPONENT_SWIZZLE_R); // TODO(b/129523279) + samplerState.swizzleG = SWIZZLE_GREEN; ASSERT(imageView->getComponentMapping().g == VK_COMPONENT_SWIZZLE_G); // TODO(b/129523279) + samplerState.swizzleB = SWIZZLE_BLUE; ASSERT(imageView->getComponentMapping().b == VK_COMPONENT_SWIZZLE_B); // TODO(b/129523279) + samplerState.swizzleA = SWIZZLE_ALPHA; ASSERT(imageView->getComponentMapping().a == VK_COMPONENT_SWIZZLE_A); // TODO(b/129523279) + samplerState.highPrecisionFiltering = false; + samplerState.compare = COMPARE_BYPASS; ASSERT(sampler->compareEnable == VK_FALSE); // TODO(b/129523279) + +// minLod // TODO(b/129523279) +// maxLod // TODO(b/129523279) +// borderColor // TODO(b/129523279) + ASSERT(sampler->mipLodBias == 0.0f); // TODO(b/129523279) + ASSERT(sampler->anisotropyEnable == VK_FALSE); // TODO(b/129523279) + ASSERT(sampler->unnormalizedCoordinates == VK_FALSE); // TODO(b/129523279) + + SamplerCore s(constants, samplerState); + + 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) + 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 = s.sampleTextureF(texture, u, v, w, q, bias, dsx, dsy, offset, samplerFunction); + + if(!vk::Format(imageView->getFormat()).isNonNormalizedInteger()) + { + Pointer<SIMD::Float> rgba = out; + rgba[0] = sample.x; + rgba[1] = sample.y; + rgba[2] = sample.z; + rgba[3] = sample.w; + } + else + { + // TODO(b/129523279): Add a Sampler::sampleTextureI() method. + Pointer<SIMD::Int> rgba = out; + rgba[0] = As<SIMD::Int>(sample.x * SIMD::Float(0xFF)); + rgba[1] = As<SIMD::Int>(sample.y * SIMD::Float(0xFF)); + rgba[2] = As<SIMD::Int>(sample.z * SIMD::Float(0xFF)); + rgba[3] = As<SIMD::Int>(sample.w * SIMD::Float(0xFF)); + } +} + +} // namespace sw \ No newline at end of file
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj index 59e8098..fa3a517 100644 --- a/src/Vulkan/vulkan.vcxproj +++ b/src/Vulkan/vulkan.vcxproj
@@ -160,6 +160,7 @@ <ClCompile Include="..\Pipeline\SetupRoutine.cpp" /> <ClCompile Include="..\Pipeline\ShaderCore.cpp" /> <ClCompile Include="..\Pipeline\SpirvShader.cpp" /> + <ClCompile Include="..\Pipeline\SpirvShaderSampling.cpp" /> <ClCompile Include="..\Pipeline\SpirvShader_dbg.cpp" /> <ClCompile Include="..\Pipeline\VertexProgram.cpp" /> <ClCompile Include="..\Pipeline\VertexRoutine.cpp" />
diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters index 9c99109..c95a986 100644 --- a/src/Vulkan/vulkan.vcxproj.filters +++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -252,6 +252,9 @@ <ClCompile Include="..\Pipeline\SpirvShader.cpp"> <Filter>Source Files\Pipeline</Filter> </ClCompile> + <ClCompile Include="..\Pipeline\SpirvShaderSampling.cpp"> + <Filter>Source Files\Pipeline</Filter> + </ClCompile> <ClCompile Include="..\Pipeline\SpirvShader_dbg.cpp"> <Filter>Source Files\Pipeline</Filter> </ClCompile>