Cache WGSL -> GLSL compilation
Fixed: dawn:1480 Change-Id: I5c1453a4e37d0e97805391a6c807091d0a8fc1c7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98281 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
e62fbbc75c
commit
8830991b41
|
@ -62,6 +62,10 @@ bool OpenGLVersion::IsES() const {
|
||||||
return mStandard == Standard::ES;
|
return mStandard == Standard::ES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLVersion::Standard OpenGLVersion::GetStandard() const {
|
||||||
|
return mStandard;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t OpenGLVersion::GetMajor() const {
|
uint32_t OpenGLVersion::GetMajor() const {
|
||||||
return mMajorVersion;
|
return mMajorVersion;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,21 @@ namespace dawn::native::opengl {
|
||||||
|
|
||||||
struct OpenGLVersion {
|
struct OpenGLVersion {
|
||||||
public:
|
public:
|
||||||
|
enum class Standard {
|
||||||
|
Desktop,
|
||||||
|
ES,
|
||||||
|
};
|
||||||
|
|
||||||
MaybeError Initialize(GetProcAddress getProc);
|
MaybeError Initialize(GetProcAddress getProc);
|
||||||
|
|
||||||
bool IsDesktop() const;
|
bool IsDesktop() const;
|
||||||
bool IsES() const;
|
bool IsES() const;
|
||||||
|
Standard GetStandard() const;
|
||||||
uint32_t GetMajor() const;
|
uint32_t GetMajor() const;
|
||||||
uint32_t GetMinor() const;
|
uint32_t GetMinor() const;
|
||||||
bool IsAtLeast(uint32_t majorVersion, uint32_t minorVersion) const;
|
bool IsAtLeast(uint32_t majorVersion, uint32_t minorVersion) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Standard {
|
|
||||||
Desktop,
|
|
||||||
ES,
|
|
||||||
};
|
|
||||||
uint32_t mMajorVersion;
|
uint32_t mMajorVersion;
|
||||||
uint32_t mMinorVersion;
|
uint32_t mMinorVersion;
|
||||||
Standard mStandard;
|
Standard mStandard;
|
||||||
|
|
|
@ -30,22 +30,6 @@
|
||||||
|
|
||||||
namespace dawn::native::opengl {
|
namespace dawn::native::opengl {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
GLenum GLShaderType(SingleShaderStage stage) {
|
|
||||||
switch (stage) {
|
|
||||||
case SingleShaderStage::Vertex:
|
|
||||||
return GL_VERTEX_SHADER;
|
|
||||||
case SingleShaderStage::Fragment:
|
|
||||||
return GL_FRAGMENT_SHADER;
|
|
||||||
case SingleShaderStage::Compute:
|
|
||||||
return GL_COMPUTE_SHADER;
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
PipelineGL::PipelineGL() : mProgram(0) {}
|
PipelineGL::PipelineGL() : mProgram(0) {}
|
||||||
|
|
||||||
PipelineGL::~PipelineGL() = default;
|
PipelineGL::~PipelineGL() = default;
|
||||||
|
@ -53,28 +37,6 @@ PipelineGL::~PipelineGL() = default;
|
||||||
MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
|
MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
|
||||||
const PipelineLayout* layout,
|
const PipelineLayout* layout,
|
||||||
const PerStage<ProgrammableStage>& stages) {
|
const PerStage<ProgrammableStage>& stages) {
|
||||||
auto CreateShader = [](const OpenGLFunctions& gl, GLenum type,
|
|
||||||
const char* source) -> ResultOrError<GLuint> {
|
|
||||||
GLuint shader = gl.CreateShader(type);
|
|
||||||
gl.ShaderSource(shader, 1, &source, nullptr);
|
|
||||||
gl.CompileShader(shader);
|
|
||||||
|
|
||||||
GLint compileStatus = GL_FALSE;
|
|
||||||
gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
|
|
||||||
if (compileStatus == GL_FALSE) {
|
|
||||||
GLint infoLogLength = 0;
|
|
||||||
gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
||||||
|
|
||||||
if (infoLogLength > 1) {
|
|
||||||
std::vector<char> buffer(infoLogLength);
|
|
||||||
gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
|
|
||||||
return DAWN_FORMAT_VALIDATION_ERROR("%s\nProgram compilation failed:\n%s", source,
|
|
||||||
buffer.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shader;
|
|
||||||
};
|
|
||||||
|
|
||||||
mProgram = gl.CreateProgram();
|
mProgram = gl.CreateProgram();
|
||||||
|
|
||||||
// Compute the set of active stages.
|
// Compute the set of active stages.
|
||||||
|
@ -91,12 +53,10 @@ MaybeError PipelineGL::InitializeBase(const OpenGLFunctions& gl,
|
||||||
std::vector<GLuint> glShaders;
|
std::vector<GLuint> glShaders;
|
||||||
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;
|
|
||||||
DAWN_TRY_ASSIGN(glsl, module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage,
|
|
||||||
&combinedSamplers[stage], layout,
|
|
||||||
&needsPlaceholderSampler));
|
|
||||||
GLuint shader;
|
GLuint shader;
|
||||||
DAWN_TRY_ASSIGN(shader, CreateShader(gl, GLShaderType(stage), glsl.c_str()));
|
DAWN_TRY_ASSIGN(shader,
|
||||||
|
module->CompileShader(gl, stages[stage], stage, &combinedSamplers[stage],
|
||||||
|
layout, &needsPlaceholderSampler));
|
||||||
gl.AttachShader(mProgram, shader);
|
gl.AttachShader(mProgram, shader);
|
||||||
glShaders.push_back(shader);
|
glShaders.push_back(shader);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,110 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "dawn/native/BindGroupLayout.h"
|
#include "dawn/native/BindGroupLayout.h"
|
||||||
|
#include "dawn/native/CacheRequest.h"
|
||||||
|
#include "dawn/native/Pipeline.h"
|
||||||
#include "dawn/native/TintUtils.h"
|
#include "dawn/native/TintUtils.h"
|
||||||
#include "dawn/native/opengl/DeviceGL.h"
|
#include "dawn/native/opengl/DeviceGL.h"
|
||||||
#include "dawn/native/opengl/PipelineLayoutGL.h"
|
#include "dawn/native/opengl/PipelineLayoutGL.h"
|
||||||
|
#include "dawn/native/stream/BlobSource.h"
|
||||||
|
#include "dawn/native/stream/ByteVectorSink.h"
|
||||||
#include "dawn/platform/DawnPlatform.h"
|
#include "dawn/platform/DawnPlatform.h"
|
||||||
#include "dawn/platform/tracing/TraceEvent.h"
|
#include "dawn/platform/tracing/TraceEvent.h"
|
||||||
|
|
||||||
#include "tint/tint.h"
|
#include "tint/tint.h"
|
||||||
|
|
||||||
|
namespace dawn::native {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
GLenum GLShaderType(SingleShaderStage stage) {
|
||||||
|
switch (stage) {
|
||||||
|
case SingleShaderStage::Vertex:
|
||||||
|
return GL_VERTEX_SHADER;
|
||||||
|
case SingleShaderStage::Fragment:
|
||||||
|
return GL_FRAGMENT_SHADER;
|
||||||
|
case SingleShaderStage::Compute:
|
||||||
|
return GL_COMPUTE_SHADER;
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
tint::writer::glsl::Version::Standard ToTintGLStandard(opengl::OpenGLVersion::Standard standard) {
|
||||||
|
switch (standard) {
|
||||||
|
case opengl::OpenGLVersion::Standard::Desktop:
|
||||||
|
return tint::writer::glsl::Version::Standard::kDesktop;
|
||||||
|
case opengl::OpenGLVersion::Standard::ES:
|
||||||
|
return tint::writer::glsl::Version::Standard::kES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using BindingMap = std::unordered_map<tint::sem::BindingPoint, tint::sem::BindingPoint>;
|
||||||
|
|
||||||
|
#define GLSL_COMPILATION_REQUEST_MEMBERS(X) \
|
||||||
|
X(const tint::Program*, inputProgram) \
|
||||||
|
X(std::string, entryPointName) \
|
||||||
|
X(tint::transform::MultiplanarExternalTexture::BindingsMap, externalTextureBindings) \
|
||||||
|
X(BindingMap, glBindings) \
|
||||||
|
X(opengl::OpenGLVersion::Standard, glVersionStandard) \
|
||||||
|
X(uint32_t, glVersionMajor) \
|
||||||
|
X(uint32_t, glVersionMinor)
|
||||||
|
|
||||||
|
DAWN_MAKE_CACHE_REQUEST(GLSLCompilationRequest, GLSL_COMPILATION_REQUEST_MEMBERS);
|
||||||
|
#undef GLSL_COMPILATION_REQUEST_MEMBERS
|
||||||
|
|
||||||
|
#define GLSL_COMPILATION_MEMBERS(X) \
|
||||||
|
X(std::string, glsl) \
|
||||||
|
X(bool, needsPlaceholderSampler) \
|
||||||
|
X(opengl::CombinedSamplerInfo, combinedSamplerInfo)
|
||||||
|
struct GLSLCompilation {
|
||||||
|
DAWN_VISITABLE_MEMBERS(GLSL_COMPILATION_MEMBERS)
|
||||||
|
#undef GLSL_COMPILATION_MEMBERS
|
||||||
|
|
||||||
|
static ResultOrError<GLSLCompilation> FromBlob(Blob blob) {
|
||||||
|
stream::BlobSource source(std::move(blob));
|
||||||
|
GLSLCompilation out;
|
||||||
|
DAWN_TRY(out.VisitAll([&](auto&... members) { return StreamOut(&source, &members...); }));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void BlobCache::Store<GLSLCompilation>(const CacheKey& key, const GLSLCompilation& c) {
|
||||||
|
stream::ByteVectorSink sink;
|
||||||
|
c.VisitAll([&](const auto&... members) { StreamIn(&sink, members...); });
|
||||||
|
Store(key, CreateBlob(std::move(sink)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void stream::Stream<opengl::BindingLocation>::Write(
|
||||||
|
stream::Sink* s,
|
||||||
|
const opengl::BindingLocation& bindingLocation) {
|
||||||
|
bindingLocation.VisitAll([&](auto&... members) { return StreamIn(s, members...); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MaybeError stream::Stream<opengl::BindingLocation>::Read(stream::Source* s,
|
||||||
|
opengl::BindingLocation* bindingLocation) {
|
||||||
|
return bindingLocation->VisitAll([&](auto&... members) { return StreamOut(s, &members...); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void stream::Stream<opengl::CombinedSampler>::Write(
|
||||||
|
stream::Sink* s,
|
||||||
|
const opengl::CombinedSampler& combinedSampler) {
|
||||||
|
combinedSampler.VisitAll([&](auto&... members) { return StreamIn(s, members...); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MaybeError stream::Stream<opengl::CombinedSampler>::Read(stream::Source* s,
|
||||||
|
opengl::CombinedSampler* combinedSampler) {
|
||||||
|
return combinedSampler->VisitAll([&](auto&... members) { return StreamOut(s, &members...); });
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dawn::native
|
||||||
|
|
||||||
namespace dawn::native::opengl {
|
namespace dawn::native::opengl {
|
||||||
|
|
||||||
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber) {
|
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber) {
|
||||||
|
@ -81,104 +177,146 @@ MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult,
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultOrError<std::string> ShaderModule::TranslateToGLSL(const char* entryPointName,
|
ResultOrError<GLuint> ShaderModule::CompileShader(const OpenGLFunctions& gl,
|
||||||
SingleShaderStage stage,
|
const ProgrammableStage& programmableStage,
|
||||||
CombinedSamplerInfo* combinedSamplers,
|
SingleShaderStage stage,
|
||||||
const PipelineLayout* layout,
|
CombinedSamplerInfo* combinedSamplers,
|
||||||
bool* needsPlaceholderSampler) const {
|
const PipelineLayout* layout,
|
||||||
|
bool* needsPlaceholderSampler) const {
|
||||||
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL");
|
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL");
|
||||||
tint::transform::Manager transformManager;
|
|
||||||
tint::transform::DataMap transformInputs;
|
|
||||||
|
|
||||||
auto externalTextureBindings = BuildExternalTextureTransformBindings(layout);
|
|
||||||
if (!externalTextureBindings.empty()) {
|
|
||||||
transformManager.Add<tint::transform::MultiplanarExternalTexture>();
|
|
||||||
transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
|
|
||||||
std::move(externalTextureBindings));
|
|
||||||
}
|
|
||||||
|
|
||||||
tint::Program program;
|
|
||||||
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(), transformInputs,
|
|
||||||
nullptr, nullptr));
|
|
||||||
const OpenGLVersion& version = ToBackend(GetDevice())->GetGL().GetVersion();
|
const OpenGLVersion& version = ToBackend(GetDevice())->GetGL().GetVersion();
|
||||||
|
|
||||||
tint::writer::glsl::Options tintOptions;
|
|
||||||
using Version = tint::writer::glsl::Version;
|
|
||||||
tintOptions.version =
|
|
||||||
Version(version.IsDesktop() ? Version::Standard::kDesktop : Version::Standard::kES,
|
|
||||||
version.GetMajor(), version.GetMinor());
|
|
||||||
|
|
||||||
using tint::transform::BindingPoint;
|
using tint::transform::BindingPoint;
|
||||||
// When textures are accessed without a sampler (e.g., textureLoad()),
|
|
||||||
// GetSamplerTextureUses() will return this sentinel value.
|
|
||||||
BindingPoint placeholderBindingPoint{static_cast<uint32_t>(kMaxBindGroupsTyped), 0};
|
|
||||||
|
|
||||||
tint::inspector::Inspector inspector(&program);
|
|
||||||
// Find all the sampler/texture pairs for this entry point, and create
|
|
||||||
// CombinedSamplers for them. CombinedSampler records the binding points
|
|
||||||
// of the original texture and sampler, and generates a unique name. The
|
|
||||||
// corresponding uniforms will be retrieved by these generated names
|
|
||||||
// in PipelineGL. Any texture-only references will have
|
|
||||||
// "usePlaceholderSampler" set to true, and only the texture binding point
|
|
||||||
// will be used in naming them. In addition, Dawn will bind a
|
|
||||||
// non-filtering sampler for them (see PipelineGL).
|
|
||||||
auto uses = inspector.GetSamplerTextureUses(entryPointName, placeholderBindingPoint);
|
|
||||||
for (const auto& use : uses) {
|
|
||||||
combinedSamplers->emplace_back();
|
|
||||||
|
|
||||||
CombinedSampler* info = &combinedSamplers->back();
|
|
||||||
if (use.sampler_binding_point == placeholderBindingPoint) {
|
|
||||||
info->usePlaceholderSampler = true;
|
|
||||||
*needsPlaceholderSampler = true;
|
|
||||||
} else {
|
|
||||||
info->usePlaceholderSampler = false;
|
|
||||||
}
|
|
||||||
info->samplerLocation.group = BindGroupIndex(use.sampler_binding_point.group);
|
|
||||||
info->samplerLocation.binding = BindingNumber(use.sampler_binding_point.binding);
|
|
||||||
info->textureLocation.group = BindGroupIndex(use.texture_binding_point.group);
|
|
||||||
info->textureLocation.binding = BindingNumber(use.texture_binding_point.binding);
|
|
||||||
tintOptions.binding_map[use] = info->GetName();
|
|
||||||
}
|
|
||||||
if (*needsPlaceholderSampler) {
|
|
||||||
tintOptions.placeholder_binding_point = placeholderBindingPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since (non-Vulkan) GLSL does not support descriptor sets, generate a
|
// Since (non-Vulkan) GLSL does not support descriptor sets, generate a
|
||||||
// mapping from the original group/binding pair to a binding-only
|
// mapping from the original group/binding pair to a binding-only
|
||||||
// value. This mapping will be used by Tint to remap all global
|
// value. This mapping will be used by Tint to remap all global
|
||||||
// variables to the 1D space.
|
// variables to the 1D space.
|
||||||
|
const BindingInfoArray& moduleBindingInfo =
|
||||||
|
GetEntryPoint(programmableStage.entryPoint).bindings;
|
||||||
|
std::unordered_map<tint::sem::BindingPoint, tint::sem::BindingPoint> glBindings;
|
||||||
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
|
for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
|
||||||
const BindGroupLayoutBase::BindingMap& bindingMap =
|
const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(group);
|
||||||
layout->GetBindGroupLayout(group)->GetBindingMap();
|
const auto& groupBindingInfo = moduleBindingInfo[group];
|
||||||
for (const auto& it : bindingMap) {
|
for (const auto& [bindingNumber, bindingInfo] : groupBindingInfo) {
|
||||||
BindingNumber bindingNumber = it.first;
|
BindingIndex bindingIndex = bgl->GetBindingIndex(bindingNumber);
|
||||||
BindingIndex bindingIndex = it.second;
|
GLuint shaderIndex = layout->GetBindingIndexInfo()[group][bindingIndex];
|
||||||
const BindingInfo& bindingInfo =
|
|
||||||
layout->GetBindGroupLayout(group)->GetBindingInfo(bindingIndex);
|
|
||||||
if (!(bindingInfo.visibility & StageBit(stage))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t shaderIndex = layout->GetBindingIndexInfo()[group][bindingIndex];
|
|
||||||
BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
|
BindingPoint srcBindingPoint{static_cast<uint32_t>(group),
|
||||||
static_cast<uint32_t>(bindingNumber)};
|
static_cast<uint32_t>(bindingNumber)};
|
||||||
BindingPoint dstBindingPoint{0, shaderIndex};
|
BindingPoint dstBindingPoint{0, shaderIndex};
|
||||||
tintOptions.binding_points.emplace(srcBindingPoint, dstBindingPoint);
|
if (srcBindingPoint != dstBindingPoint) {
|
||||||
|
glBindings.emplace(srcBindingPoint, dstBindingPoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tintOptions.allow_collisions = true;
|
|
||||||
}
|
}
|
||||||
auto result = tint::writer::glsl::Generate(&program, tintOptions, entryPointName);
|
|
||||||
DAWN_INVALID_IF(!result.success, "An error occured while generating GLSL: %s.", result.error);
|
GLSLCompilationRequest req = {};
|
||||||
std::string glsl = std::move(result.glsl);
|
req.inputProgram = GetTintProgram();
|
||||||
|
req.entryPointName = programmableStage.entryPoint;
|
||||||
|
req.externalTextureBindings = BuildExternalTextureTransformBindings(layout);
|
||||||
|
req.glBindings = std::move(glBindings);
|
||||||
|
req.glVersionStandard = version.GetStandard();
|
||||||
|
req.glVersionMajor = version.GetMajor();
|
||||||
|
req.glVersionMinor = version.GetMinor();
|
||||||
|
|
||||||
|
CacheResult<GLSLCompilation> compilationResult;
|
||||||
|
DAWN_TRY_LOAD_OR_RUN(
|
||||||
|
compilationResult, GetDevice(), std::move(req), GLSLCompilation::FromBlob,
|
||||||
|
[](GLSLCompilationRequest r) -> ResultOrError<GLSLCompilation> {
|
||||||
|
tint::transform::Manager transformManager;
|
||||||
|
tint::transform::DataMap transformInputs;
|
||||||
|
|
||||||
|
if (!r.externalTextureBindings.empty()) {
|
||||||
|
transformManager.Add<tint::transform::MultiplanarExternalTexture>();
|
||||||
|
transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
|
||||||
|
std::move(r.externalTextureBindings));
|
||||||
|
}
|
||||||
|
|
||||||
|
tint::Program program;
|
||||||
|
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, r.inputProgram,
|
||||||
|
transformInputs, nullptr, nullptr));
|
||||||
|
|
||||||
|
tint::writer::glsl::Options tintOptions;
|
||||||
|
tintOptions.version = tint::writer::glsl::Version(ToTintGLStandard(r.glVersionStandard),
|
||||||
|
r.glVersionMajor, r.glVersionMinor);
|
||||||
|
|
||||||
|
// When textures are accessed without a sampler (e.g., textureLoad()),
|
||||||
|
// GetSamplerTextureUses() will return this sentinel value.
|
||||||
|
BindingPoint placeholderBindingPoint{static_cast<uint32_t>(kMaxBindGroupsTyped), 0};
|
||||||
|
|
||||||
|
bool needsPlaceholderSampler = false;
|
||||||
|
tint::inspector::Inspector inspector(&program);
|
||||||
|
// Find all the sampler/texture pairs for this entry point, and create
|
||||||
|
// CombinedSamplers for them. CombinedSampler records the binding points
|
||||||
|
// of the original texture and sampler, and generates a unique name. The
|
||||||
|
// corresponding uniforms will be retrieved by these generated names
|
||||||
|
// in PipelineGL. Any texture-only references will have
|
||||||
|
// "usePlaceholderSampler" set to true, and only the texture binding point
|
||||||
|
// will be used in naming them. In addition, Dawn will bind a
|
||||||
|
// non-filtering sampler for them (see PipelineGL).
|
||||||
|
auto uses = inspector.GetSamplerTextureUses(r.entryPointName, placeholderBindingPoint);
|
||||||
|
CombinedSamplerInfo combinedSamplerInfo;
|
||||||
|
for (const auto& use : uses) {
|
||||||
|
combinedSamplerInfo.emplace_back();
|
||||||
|
|
||||||
|
CombinedSampler* info = &combinedSamplerInfo.back();
|
||||||
|
if (use.sampler_binding_point == placeholderBindingPoint) {
|
||||||
|
info->usePlaceholderSampler = true;
|
||||||
|
needsPlaceholderSampler = true;
|
||||||
|
tintOptions.placeholder_binding_point = placeholderBindingPoint;
|
||||||
|
} else {
|
||||||
|
info->usePlaceholderSampler = false;
|
||||||
|
}
|
||||||
|
info->samplerLocation.group = BindGroupIndex(use.sampler_binding_point.group);
|
||||||
|
info->samplerLocation.binding = BindingNumber(use.sampler_binding_point.binding);
|
||||||
|
info->textureLocation.group = BindGroupIndex(use.texture_binding_point.group);
|
||||||
|
info->textureLocation.binding = BindingNumber(use.texture_binding_point.binding);
|
||||||
|
tintOptions.binding_map[use] = info->GetName();
|
||||||
|
}
|
||||||
|
tintOptions.binding_points = std::move(r.glBindings);
|
||||||
|
tintOptions.allow_collisions = true;
|
||||||
|
|
||||||
|
auto result = tint::writer::glsl::Generate(&program, tintOptions, r.entryPointName);
|
||||||
|
DAWN_INVALID_IF(!result.success, "An error occured while generating GLSL: %s.",
|
||||||
|
result.error);
|
||||||
|
|
||||||
|
return GLSLCompilation{std::move(result.glsl), needsPlaceholderSampler,
|
||||||
|
std::move(combinedSamplerInfo)};
|
||||||
|
});
|
||||||
|
|
||||||
if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
|
if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
|
||||||
std::ostringstream dumpedMsg;
|
std::ostringstream dumpedMsg;
|
||||||
dumpedMsg << "/* Dumped generated GLSL */" << std::endl << glsl;
|
dumpedMsg << "/* Dumped generated GLSL */" << std::endl << compilationResult->glsl;
|
||||||
|
|
||||||
GetDevice()->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
|
GetDevice()->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return glsl;
|
GLuint shader = gl.CreateShader(GLShaderType(stage));
|
||||||
|
const char* source = compilationResult->glsl.c_str();
|
||||||
|
gl.ShaderSource(shader, 1, &source, nullptr);
|
||||||
|
gl.CompileShader(shader);
|
||||||
|
|
||||||
|
GLint compileStatus = GL_FALSE;
|
||||||
|
gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
|
||||||
|
if (compileStatus == GL_FALSE) {
|
||||||
|
GLint infoLogLength = 0;
|
||||||
|
gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||||
|
|
||||||
|
if (infoLogLength > 1) {
|
||||||
|
std::vector<char> buffer(infoLogLength);
|
||||||
|
gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
|
||||||
|
gl.DeleteShader(shader);
|
||||||
|
return DAWN_FORMAT_VALIDATION_ERROR("%s\nProgram compilation failed:\n%s", source,
|
||||||
|
buffer.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BlobCache* cache = GetDevice()->GetBlobCache()) {
|
||||||
|
cache->EnsureStored(compilationResult);
|
||||||
|
}
|
||||||
|
*needsPlaceholderSampler = compilationResult->needsPlaceholderSampler;
|
||||||
|
*combinedSamplers = std::move(compilationResult->combinedSamplerInfo);
|
||||||
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dawn::native::opengl
|
} // namespace dawn::native::opengl
|
||||||
|
|
|
@ -21,37 +21,53 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dawn/native/ShaderModule.h"
|
#include "dawn/native/ShaderModule.h"
|
||||||
|
#include "dawn/native/VisitableMembers.h"
|
||||||
#include "dawn/native/opengl/opengl_platform.h"
|
#include "dawn/native/opengl/opengl_platform.h"
|
||||||
|
|
||||||
namespace dawn::native::opengl {
|
namespace dawn::native {
|
||||||
|
|
||||||
|
struct ProgrammableStage;
|
||||||
|
|
||||||
|
namespace stream {
|
||||||
|
class Sink;
|
||||||
|
class Source;
|
||||||
|
} // namespace stream
|
||||||
|
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
class PipelineLayout;
|
class PipelineLayout;
|
||||||
|
struct OpenGLFunctions;
|
||||||
|
|
||||||
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber);
|
std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber);
|
||||||
|
|
||||||
|
#define BINDING_LOCATION_MEMBERS(X) \
|
||||||
|
X(BindGroupIndex, group) \
|
||||||
|
X(BindingNumber, binding)
|
||||||
struct BindingLocation {
|
struct BindingLocation {
|
||||||
BindGroupIndex group;
|
DAWN_VISITABLE_MEMBERS(BINDING_LOCATION_MEMBERS)
|
||||||
BindingNumber binding;
|
#undef BINDING_LOCATION_MEMBERS
|
||||||
};
|
};
|
||||||
bool operator<(const BindingLocation& a, const BindingLocation& b);
|
bool operator<(const BindingLocation& a, const BindingLocation& b);
|
||||||
|
|
||||||
|
#define COMBINED_SAMPLER_MEMBERS(X) \
|
||||||
|
X(BindingLocation, samplerLocation) \
|
||||||
|
X(BindingLocation, textureLocation) \
|
||||||
|
/* OpenGL requires a sampler with texelFetch. If this is true, the developer did not */ \
|
||||||
|
/* provide one and Dawn should bind a placeholder non-filtering sampler; */ \
|
||||||
|
/* |samplerLocation| is unused. */ \
|
||||||
|
X(bool, usePlaceholderSampler)
|
||||||
|
|
||||||
struct CombinedSampler {
|
struct CombinedSampler {
|
||||||
BindingLocation samplerLocation;
|
DAWN_VISITABLE_MEMBERS(COMBINED_SAMPLER_MEMBERS)
|
||||||
BindingLocation textureLocation;
|
#undef COMBINED_SAMPLER_MEMBERS
|
||||||
// OpenGL requires a sampler with texelFetch. If this is true, the developer did not provide
|
|
||||||
// one and Dawn should bind a placeholder non-filtering sampler. |samplerLocation| is
|
|
||||||
// unused.
|
|
||||||
bool usePlaceholderSampler;
|
|
||||||
std::string GetName() const;
|
std::string GetName() const;
|
||||||
};
|
};
|
||||||
bool operator<(const CombinedSampler& a, const CombinedSampler& b);
|
bool operator<(const CombinedSampler& a, const CombinedSampler& b);
|
||||||
|
|
||||||
using CombinedSamplerInfo = std::vector<CombinedSampler>;
|
using CombinedSamplerInfo = std::vector<CombinedSampler>;
|
||||||
|
|
||||||
using BindingInfoArrayTable = std::unordered_map<std::string, std::unique_ptr<BindingInfoArray>>;
|
|
||||||
|
|
||||||
class ShaderModule final : public ShaderModuleBase {
|
class ShaderModule final : public ShaderModuleBase {
|
||||||
public:
|
public:
|
||||||
static ResultOrError<Ref<ShaderModule>> Create(Device* device,
|
static ResultOrError<Ref<ShaderModule>> Create(Device* device,
|
||||||
|
@ -59,11 +75,12 @@ class ShaderModule final : public ShaderModuleBase {
|
||||||
ShaderModuleParseResult* parseResult,
|
ShaderModuleParseResult* parseResult,
|
||||||
OwnedCompilationMessages* compilationMessages);
|
OwnedCompilationMessages* compilationMessages);
|
||||||
|
|
||||||
ResultOrError<std::string> TranslateToGLSL(const char* entryPointName,
|
ResultOrError<GLuint> CompileShader(const OpenGLFunctions& gl,
|
||||||
SingleShaderStage stage,
|
const ProgrammableStage& programmableStage,
|
||||||
CombinedSamplerInfo* combinedSamplers,
|
SingleShaderStage stage,
|
||||||
const PipelineLayout* layout,
|
CombinedSamplerInfo* combinedSamplers,
|
||||||
bool* needsPlaceholderSampler) const;
|
const PipelineLayout* layout,
|
||||||
|
bool* needsPlaceholderSampler) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
|
ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor);
|
||||||
|
@ -72,6 +89,7 @@ class ShaderModule final : public ShaderModuleBase {
|
||||||
OwnedCompilationMessages* compilationMessages);
|
OwnedCompilationMessages* compilationMessages);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn::native::opengl
|
} // namespace opengl
|
||||||
|
} // namespace dawn::native
|
||||||
|
|
||||||
#endif // SRC_DAWN_NATIVE_OPENGL_SHADERMODULEGL_H_
|
#endif // SRC_DAWN_NATIVE_OPENGL_SHADERMODULEGL_H_
|
||||||
|
|
|
@ -108,8 +108,8 @@ class PipelineCachingTests : public DawnTest {
|
||||||
const EntryCounts counts = {
|
const EntryCounts counts = {
|
||||||
// pipeline caching is only implemented on D3D12/Vulkan
|
// pipeline caching is only implemented on D3D12/Vulkan
|
||||||
IsD3D12() || IsVulkan() ? 1u : 0u,
|
IsD3D12() || IsVulkan() ? 1u : 0u,
|
||||||
// shader module caching is only implemented on Vulkan/D3D12/Metal
|
// One blob per shader module
|
||||||
IsVulkan() || IsMetal() || IsD3D12() ? 1u : 0u,
|
1u,
|
||||||
};
|
};
|
||||||
NiceMock<CachingInterfaceMock> mMockCache;
|
NiceMock<CachingInterfaceMock> mMockCache;
|
||||||
};
|
};
|
||||||
|
@ -587,8 +587,8 @@ TEST_P(SinglePipelineCachingTests, RenderPipelineBlobCacheLayout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache should not hit for the fragment shader, but should hit for the pipeline.
|
// Cache should not hit for the fragment shader, but should hit for the pipeline.
|
||||||
// Except for D3D12, the shader is different but compiles to the same due to binding number
|
// On Metal and Vulkan, the shader is different but compiles to the same due to binding number
|
||||||
// remapping.
|
// remapping. On other backends, the compiled shader is different and so is the pipeline.
|
||||||
{
|
{
|
||||||
wgpu::Device device = CreateDevice();
|
wgpu::Device device = CreateDevice();
|
||||||
utils::ComboRenderPipelineDescriptor desc;
|
utils::ComboRenderPipelineDescriptor desc;
|
||||||
|
@ -605,7 +605,7 @@ TEST_P(SinglePipelineCachingTests, RenderPipelineBlobCacheLayout) {
|
||||||
{1, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform},
|
{1, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
if (!IsD3D12()) {
|
if (IsMetal() || IsVulkan()) {
|
||||||
EXPECT_CACHE_STATS(mMockCache, Hit(counts.shaderModule + counts.pipeline),
|
EXPECT_CACHE_STATS(mMockCache, Hit(counts.shaderModule + counts.pipeline),
|
||||||
Add(counts.shaderModule), device.CreateRenderPipeline(&desc));
|
Add(counts.shaderModule), device.CreateRenderPipeline(&desc));
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue