mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-04 12:16:10 +00:00
OpenGL: Bind a dummy sampler for OpImageFetch if not present
In WGSL, textureLoad translates to an OpImageFetch without the combined sampler. In OpenGL, we need to use SPIRV-Cross to insert a dummy nearest filtering sampler and bind that in the backend. Bug: dawn:585 Change-Id: I92ae6ad35263d3720e59fa93688ca914a9495a81 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/34401 Reviewed-by: Stephen White <senorblanco@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
0bc6128d4b
commit
2395ff5be1
@ -17,10 +17,12 @@
|
|||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
#include "common/Log.h"
|
#include "common/Log.h"
|
||||||
#include "dawn_native/BindGroupLayout.h"
|
#include "dawn_native/BindGroupLayout.h"
|
||||||
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/Pipeline.h"
|
#include "dawn_native/Pipeline.h"
|
||||||
#include "dawn_native/opengl/Forward.h"
|
#include "dawn_native/opengl/Forward.h"
|
||||||
#include "dawn_native/opengl/OpenGLFunctions.h"
|
#include "dawn_native/opengl/OpenGLFunctions.h"
|
||||||
#include "dawn_native/opengl/PipelineLayoutGL.h"
|
#include "dawn_native/opengl/PipelineLayoutGL.h"
|
||||||
|
#include "dawn_native/opengl/SamplerGL.h"
|
||||||
#include "dawn_native/opengl/ShaderModuleGL.h"
|
#include "dawn_native/opengl/ShaderModuleGL.h"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -42,8 +44,8 @@ namespace dawn_native { namespace opengl {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PipelineGL::PipelineGL() {
|
PipelineGL::PipelineGL() = default;
|
||||||
}
|
PipelineGL::~PipelineGL() = default;
|
||||||
|
|
||||||
void PipelineGL::Initialize(const OpenGLFunctions& gl,
|
void PipelineGL::Initialize(const OpenGLFunctions& gl,
|
||||||
const PipelineLayout* layout,
|
const PipelineLayout* layout,
|
||||||
@ -82,14 +84,25 @@ namespace dawn_native { namespace opengl {
|
|||||||
|
|
||||||
// Create an OpenGL shader for each stage and gather the list of combined samplers.
|
// Create an OpenGL shader for each stage and gather the list of combined samplers.
|
||||||
PerStage<CombinedSamplerInfo> combinedSamplers;
|
PerStage<CombinedSamplerInfo> combinedSamplers;
|
||||||
|
bool needsDummySampler = false;
|
||||||
for (SingleShaderStage stage : IterateStages(activeStages)) {
|
for (SingleShaderStage stage : IterateStages(activeStages)) {
|
||||||
const ShaderModule* module = ToBackend(stages[stage].module.Get());
|
const ShaderModule* module = ToBackend(stages[stage].module.Get());
|
||||||
std::string glsl = module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage,
|
std::string glsl =
|
||||||
&combinedSamplers[stage], layout);
|
module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage,
|
||||||
|
&combinedSamplers[stage], layout, &needsDummySampler);
|
||||||
GLuint shader = CreateShader(gl, GLShaderType(stage), glsl.c_str());
|
GLuint shader = CreateShader(gl, GLShaderType(stage), glsl.c_str());
|
||||||
gl.AttachShader(mProgram, shader);
|
gl.AttachShader(mProgram, shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needsDummySampler) {
|
||||||
|
SamplerDescriptor desc = {};
|
||||||
|
ASSERT(desc.minFilter == wgpu::FilterMode::Nearest);
|
||||||
|
ASSERT(desc.magFilter == wgpu::FilterMode::Nearest);
|
||||||
|
ASSERT(desc.mipmapFilter == wgpu::FilterMode::Nearest);
|
||||||
|
mDummySampler = AcquireRef(
|
||||||
|
ToBackend(layout->GetDevice()->GetOrCreateSampler(&desc).AcquireSuccess()));
|
||||||
|
}
|
||||||
|
|
||||||
// Link all the shaders together.
|
// Link all the shaders together.
|
||||||
gl.LinkProgram(mProgram);
|
gl.LinkProgram(mProgram);
|
||||||
|
|
||||||
@ -204,13 +217,18 @@ namespace dawn_native { namespace opengl {
|
|||||||
wgpu::TextureComponentType::Float;
|
wgpu::TextureComponentType::Float;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
if (combined.useDummySampler) {
|
||||||
|
mDummySamplerUnits.push_back(textureUnit);
|
||||||
|
} else {
|
||||||
const BindGroupLayoutBase* bgl =
|
const BindGroupLayoutBase* bgl =
|
||||||
layout->GetBindGroupLayout(combined.samplerLocation.group);
|
layout->GetBindGroupLayout(combined.samplerLocation.group);
|
||||||
BindingIndex bindingIndex =
|
BindingIndex bindingIndex =
|
||||||
bgl->GetBindingIndex(combined.samplerLocation.binding);
|
bgl->GetBindingIndex(combined.samplerLocation.binding);
|
||||||
|
|
||||||
GLuint samplerIndex = indices[combined.samplerLocation.group][bindingIndex];
|
GLuint samplerIndex = indices[combined.samplerLocation.group][bindingIndex];
|
||||||
mUnitsForSamplers[samplerIndex].push_back({textureUnit, shouldUseFiltering});
|
mUnitsForSamplers[samplerIndex].push_back(
|
||||||
|
{textureUnit, shouldUseFiltering});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textureUnit++;
|
textureUnit++;
|
||||||
@ -235,6 +253,10 @@ namespace dawn_native { namespace opengl {
|
|||||||
|
|
||||||
void PipelineGL::ApplyNow(const OpenGLFunctions& gl) {
|
void PipelineGL::ApplyNow(const OpenGLFunctions& gl) {
|
||||||
gl.UseProgram(mProgram);
|
gl.UseProgram(mProgram);
|
||||||
|
for (GLuint unit : mDummySamplerUnits) {
|
||||||
|
ASSERT(mDummySampler.Get() != nullptr);
|
||||||
|
gl.BindSampler(unit, mDummySampler->GetNonFilteringHandle());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::opengl
|
}} // namespace dawn_native::opengl
|
||||||
|
@ -31,10 +31,12 @@ namespace dawn_native { namespace opengl {
|
|||||||
struct OpenGLFunctions;
|
struct OpenGLFunctions;
|
||||||
class PersistentPipelineState;
|
class PersistentPipelineState;
|
||||||
class PipelineLayout;
|
class PipelineLayout;
|
||||||
|
class Sampler;
|
||||||
|
|
||||||
class PipelineGL {
|
class PipelineGL {
|
||||||
public:
|
public:
|
||||||
PipelineGL();
|
PipelineGL();
|
||||||
|
~PipelineGL();
|
||||||
|
|
||||||
void Initialize(const OpenGLFunctions& gl,
|
void Initialize(const OpenGLFunctions& gl,
|
||||||
const PipelineLayout* layout,
|
const PipelineLayout* layout,
|
||||||
@ -56,6 +58,10 @@ namespace dawn_native { namespace opengl {
|
|||||||
GLuint mProgram;
|
GLuint mProgram;
|
||||||
std::vector<std::vector<SamplerUnit>> mUnitsForSamplers;
|
std::vector<std::vector<SamplerUnit>> mUnitsForSamplers;
|
||||||
std::vector<std::vector<GLuint>> mUnitsForTextures;
|
std::vector<std::vector<GLuint>> mUnitsForTextures;
|
||||||
|
std::vector<GLuint> mDummySamplerUnits;
|
||||||
|
// TODO(enga): This could live on the Device, or elsewhere, but currently it makes Device
|
||||||
|
// destruction complex as it requires the sampler to be destroyed before the sampler cache.
|
||||||
|
Ref<Sampler> mDummySampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace dawn_native::opengl
|
}} // namespace dawn_native::opengl
|
||||||
|
@ -39,15 +39,19 @@ namespace dawn_native { namespace opengl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const CombinedSampler& a, const CombinedSampler& b) {
|
bool operator<(const CombinedSampler& a, const CombinedSampler& b) {
|
||||||
return std::tie(a.samplerLocation, a.textureLocation) <
|
return std::tie(a.useDummySampler, a.samplerLocation, a.textureLocation) <
|
||||||
std::tie(b.samplerLocation, b.textureLocation);
|
std::tie(b.useDummySampler, a.samplerLocation, b.textureLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CombinedSampler::GetName() const {
|
std::string CombinedSampler::GetName() const {
|
||||||
std::ostringstream o;
|
std::ostringstream o;
|
||||||
o << "dawn_combined";
|
o << "dawn_combined";
|
||||||
|
if (useDummySampler) {
|
||||||
|
o << "_dummy_sampler";
|
||||||
|
} else {
|
||||||
o << "_" << static_cast<uint32_t>(samplerLocation.group) << "_"
|
o << "_" << static_cast<uint32_t>(samplerLocation.group) << "_"
|
||||||
<< static_cast<uint32_t>(samplerLocation.binding);
|
<< static_cast<uint32_t>(samplerLocation.binding);
|
||||||
|
}
|
||||||
o << "_with_" << static_cast<uint32_t>(textureLocation.group) << "_"
|
o << "_with_" << static_cast<uint32_t>(textureLocation.group) << "_"
|
||||||
<< static_cast<uint32_t>(textureLocation.binding);
|
<< static_cast<uint32_t>(textureLocation.binding);
|
||||||
return o.str();
|
return o.str();
|
||||||
@ -68,7 +72,8 @@ namespace dawn_native { namespace opengl {
|
|||||||
std::string ShaderModule::TranslateToGLSL(const char* entryPointName,
|
std::string ShaderModule::TranslateToGLSL(const char* entryPointName,
|
||||||
SingleShaderStage stage,
|
SingleShaderStage stage,
|
||||||
CombinedSamplerInfo* combinedSamplers,
|
CombinedSamplerInfo* combinedSamplers,
|
||||||
const PipelineLayout* layout) const {
|
const PipelineLayout* layout,
|
||||||
|
bool* needsDummySampler) const {
|
||||||
// If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to
|
// If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to
|
||||||
// be updated.
|
// be updated.
|
||||||
spirv_cross::CompilerGLSL::Options options;
|
spirv_cross::CompilerGLSL::Options options;
|
||||||
@ -92,6 +97,13 @@ namespace dawn_native { namespace opengl {
|
|||||||
compiler.set_common_options(options);
|
compiler.set_common_options(options);
|
||||||
compiler.set_entry_point(entryPointName, ShaderStageToExecutionModel(stage));
|
compiler.set_entry_point(entryPointName, ShaderStageToExecutionModel(stage));
|
||||||
|
|
||||||
|
// Analyzes all OpImageFetch opcodes and checks if there are instances where
|
||||||
|
// said instruction is used without a combined image sampler.
|
||||||
|
// GLSL does not support texelFetch without a sampler.
|
||||||
|
// To workaround this, we must inject a dummy sampler which can be used to form a sampler2D
|
||||||
|
// at the call-site of texelFetch as necessary.
|
||||||
|
spirv_cross::VariableID dummySamplerId = compiler.build_dummy_sampler_for_combined_images();
|
||||||
|
|
||||||
// Extract bindings names so that it can be used to get its location in program.
|
// Extract bindings names so that it can be used to get its location in program.
|
||||||
// Now translate the separate sampler / textures into combined ones and store their info. We
|
// Now translate the separate sampler / textures into combined ones and store their info. We
|
||||||
// need to do this before removing the set and binding decorations.
|
// need to do this before removing the set and binding decorations.
|
||||||
@ -101,10 +113,17 @@ namespace dawn_native { namespace opengl {
|
|||||||
combinedSamplers->emplace_back();
|
combinedSamplers->emplace_back();
|
||||||
|
|
||||||
CombinedSampler* info = &combinedSamplers->back();
|
CombinedSampler* info = &combinedSamplers->back();
|
||||||
|
if (combined.sampler_id == dummySamplerId) {
|
||||||
|
*needsDummySampler = true;
|
||||||
|
info->useDummySampler = true;
|
||||||
|
info->samplerLocation = {};
|
||||||
|
} else {
|
||||||
|
info->useDummySampler = false;
|
||||||
info->samplerLocation.group = BindGroupIndex(
|
info->samplerLocation.group = BindGroupIndex(
|
||||||
compiler.get_decoration(combined.sampler_id, spv::DecorationDescriptorSet));
|
compiler.get_decoration(combined.sampler_id, spv::DecorationDescriptorSet));
|
||||||
info->samplerLocation.binding =
|
info->samplerLocation.binding = BindingNumber(
|
||||||
BindingNumber(compiler.get_decoration(combined.sampler_id, spv::DecorationBinding));
|
compiler.get_decoration(combined.sampler_id, spv::DecorationBinding));
|
||||||
|
}
|
||||||
info->textureLocation.group = BindGroupIndex(
|
info->textureLocation.group = BindGroupIndex(
|
||||||
compiler.get_decoration(combined.image_id, spv::DecorationDescriptorSet));
|
compiler.get_decoration(combined.image_id, spv::DecorationDescriptorSet));
|
||||||
info->textureLocation.binding =
|
info->textureLocation.binding =
|
||||||
|
@ -35,6 +35,9 @@ namespace dawn_native { namespace opengl {
|
|||||||
struct CombinedSampler {
|
struct CombinedSampler {
|
||||||
BindingLocation samplerLocation;
|
BindingLocation samplerLocation;
|
||||||
BindingLocation textureLocation;
|
BindingLocation textureLocation;
|
||||||
|
// OpenGL requires a sampler with texelFetch. If this is true, the developer did not provide
|
||||||
|
// one and Dawn should bind a dummy non-filtering sampler. |samplerLocation| is unused.
|
||||||
|
bool useDummySampler;
|
||||||
std::string GetName() const;
|
std::string GetName() const;
|
||||||
};
|
};
|
||||||
bool operator<(const CombinedSampler& a, const CombinedSampler& b);
|
bool operator<(const CombinedSampler& a, const CombinedSampler& b);
|
||||||
@ -49,7 +52,8 @@ namespace dawn_native { namespace opengl {
|
|||||||
std::string TranslateToGLSL(const char* entryPointName,
|
std::string TranslateToGLSL(const char* entryPointName,
|
||||||
SingleShaderStage stage,
|
SingleShaderStage stage,
|
||||||
CombinedSamplerInfo* combinedSamplers,
|
CombinedSamplerInfo* combinedSamplers,
|
||||||
const PipelineLayout* layout) const;
|
const PipelineLayout* layout,
|
||||||
|
bool* needsDummySampler) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
|
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user