mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-21 22:13:45 +00:00
* clang/gcc: enable -pedantic warnings * suppress a GCC-specific warning in stb_image * And some clang-specific warnings * -Wconversion (clang) -Wold-style-cast (clang+gcc) and fix a few warnings that show up with these (and a few more with -Wconversion on gcc, even though that's not enabled by default) * bunch more warnings * fixes * remove merge error
214 lines
7.9 KiB
C++
214 lines
7.9 KiB
C++
// Copyright 2017 The NXT Authors
|
|
//
|
|
// 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 "backend/opengl/PipelineGL.h"
|
|
|
|
#include "backend/opengl/OpenGLBackend.h"
|
|
#include "backend/opengl/PersistentPipelineStateGL.h"
|
|
#include "backend/opengl/PipelineLayoutGL.h"
|
|
#include "backend/opengl/ShaderModuleGL.h"
|
|
|
|
#include <iostream>
|
|
#include <set>
|
|
|
|
namespace backend {
|
|
namespace opengl {
|
|
|
|
namespace {
|
|
|
|
GLenum GLShaderType(nxt::ShaderStage stage) {
|
|
switch (stage) {
|
|
case nxt::ShaderStage::Vertex:
|
|
return GL_VERTEX_SHADER;
|
|
case nxt::ShaderStage::Fragment:
|
|
return GL_FRAGMENT_SHADER;
|
|
case nxt::ShaderStage::Compute:
|
|
return GL_COMPUTE_SHADER;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
PipelineGL::PipelineGL(PipelineBase* parent, PipelineBuilder* builder) {
|
|
auto CreateShader = [](GLenum type, const char* source) -> GLuint {
|
|
GLuint shader = glCreateShader(type);
|
|
glShaderSource(shader, 1, &source, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
GLint compileStatus = GL_FALSE;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
|
|
if (compileStatus == GL_FALSE) {
|
|
GLint infoLogLength = 0;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
if (infoLogLength > 1) {
|
|
std::vector<char> buffer(infoLogLength);
|
|
glGetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
|
|
std::cout << source << std::endl;
|
|
std::cout << "Program compilation failed:\n";
|
|
std::cout << buffer.data() << std::endl;
|
|
}
|
|
}
|
|
return shader;
|
|
};
|
|
|
|
auto FillPushConstants = [](const ShaderModule* module, GLPushConstantInfo* info, GLuint program) {
|
|
const auto& moduleInfo = module->GetPushConstants();
|
|
for (uint32_t i = 0; i < moduleInfo.names.size(); i++) {
|
|
(*info)[i] = -1;
|
|
|
|
unsigned int size = moduleInfo.sizes[i];
|
|
if (size == 0) {
|
|
continue;
|
|
}
|
|
|
|
GLint location = glGetUniformLocation(program, moduleInfo.names[i].c_str());
|
|
if (location == -1) {
|
|
continue;
|
|
}
|
|
|
|
for (uint32_t offset = 0; offset < size; offset++) {
|
|
(*info)[i + offset] = location + offset;
|
|
}
|
|
i += size - 1;
|
|
}
|
|
};
|
|
|
|
program = glCreateProgram();
|
|
|
|
for (auto stage : IterateStages(parent->GetStageMask())) {
|
|
const ShaderModule* module = ToBackend(builder->GetStageInfo(stage).module.Get());
|
|
|
|
GLuint shader = CreateShader(GLShaderType(stage), module->GetSource());
|
|
glAttachShader(program, shader);
|
|
}
|
|
|
|
glLinkProgram(program);
|
|
|
|
GLint linkStatus = GL_FALSE;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
|
if (linkStatus == GL_FALSE) {
|
|
GLint infoLogLength = 0;
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
if (infoLogLength > 1) {
|
|
std::vector<char> buffer(infoLogLength);
|
|
glGetProgramInfoLog(program, infoLogLength, nullptr, &buffer[0]);
|
|
std::cout << "Program link failed:\n";
|
|
std::cout << buffer.data() << std::endl;
|
|
}
|
|
}
|
|
|
|
for (auto stage : IterateStages(parent->GetStageMask())) {
|
|
const ShaderModule* module = ToBackend(builder->GetStageInfo(stage).module.Get());
|
|
FillPushConstants(module, &glPushConstants[stage], program);
|
|
}
|
|
|
|
glUseProgram(program);
|
|
|
|
// The uniforms are part of the program state so we can pre-bind buffer units, texture units etc.
|
|
const auto& layout = ToBackend(parent->GetLayout());
|
|
const auto& indices = layout->GetBindingIndexInfo();
|
|
|
|
for (uint32_t group = 0; group < kMaxBindGroups; ++group) {
|
|
const auto& groupInfo = layout->GetBindGroupLayout(group)->GetBindingInfo();
|
|
|
|
for (uint32_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
|
|
if (!groupInfo.mask[binding]) {
|
|
continue;
|
|
}
|
|
|
|
std::string name = GetBindingName(group, binding);
|
|
switch (groupInfo.types[binding]) {
|
|
case nxt::BindingType::UniformBuffer:
|
|
{
|
|
GLint location = glGetUniformBlockIndex(program, name.c_str());
|
|
glUniformBlockBinding(program, location, indices[group][binding]);
|
|
}
|
|
break;
|
|
|
|
case nxt::BindingType::StorageBuffer:
|
|
{
|
|
GLuint location = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, name.c_str());
|
|
glShaderStorageBlockBinding(program, location, indices[group][binding]);
|
|
}
|
|
break;
|
|
|
|
case nxt::BindingType::Sampler:
|
|
case nxt::BindingType::SampledTexture:
|
|
// These binding types are handled in the separate sampler and texture emulation
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compute links between stages for combined samplers, then bind them to texture units
|
|
{
|
|
std::set<CombinedSampler> combinedSamplersSet;
|
|
for (auto stage : IterateStages(parent->GetStageMask())) {
|
|
const auto& module = ToBackend(builder->GetStageInfo(stage).module);
|
|
|
|
for (const auto& combined : module->GetCombinedSamplerInfo()) {
|
|
combinedSamplersSet.insert(combined);
|
|
}
|
|
}
|
|
|
|
unitsForSamplers.resize(layout->GetNumSamplers());
|
|
unitsForTextures.resize(layout->GetNumSampledTextures());
|
|
|
|
GLuint textureUnit = layout->GetTextureUnitsUsed();
|
|
for (const auto& combined : combinedSamplersSet) {
|
|
std::string name = combined.GetName();
|
|
GLint location = glGetUniformLocation(program, name.c_str());
|
|
glUniform1i(location, textureUnit);
|
|
|
|
GLuint samplerIndex = indices[combined.samplerLocation.group][combined.samplerLocation.binding];
|
|
unitsForSamplers[samplerIndex].push_back(textureUnit);
|
|
|
|
GLuint textureIndex = indices[combined.textureLocation.group][combined.textureLocation.binding];
|
|
unitsForTextures[textureIndex].push_back(textureUnit);
|
|
|
|
textureUnit ++;
|
|
}
|
|
}
|
|
}
|
|
|
|
const PipelineGL::GLPushConstantInfo& PipelineGL::GetGLPushConstants(nxt::ShaderStage stage) const {
|
|
return glPushConstants[stage];
|
|
}
|
|
|
|
const std::vector<GLuint>& PipelineGL::GetTextureUnitsForSampler(GLuint index) const {
|
|
ASSERT(index < unitsForSamplers.size());
|
|
return unitsForSamplers[index];
|
|
}
|
|
|
|
const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTexture(GLuint index) const {
|
|
ASSERT(index < unitsForSamplers.size());
|
|
return unitsForTextures[index];
|
|
}
|
|
|
|
GLuint PipelineGL::GetProgramHandle() const {
|
|
return program;
|
|
}
|
|
|
|
void PipelineGL::ApplyNow() {
|
|
glUseProgram(program);
|
|
}
|
|
|
|
}
|
|
}
|