Corentin Wallez | 4a9ef4e | 2018-07-18 11:40:26 +0200 | [diff] [blame] | 1 | // Copyright 2017 The Dawn Authors |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
Corentin Wallez | d37523f | 2018-07-24 13:53:51 +0200 | [diff] [blame] | 15 | #include "dawn_native/opengl/PipelineGL.h" |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 16 | |
Kai Ninomiya | 311e2a4 | 2018-06-29 18:22:02 -0700 | [diff] [blame] | 17 | #include "common/BitSetIterator.h" |
Corentin Wallez | 95586ff | 2019-12-05 11:13:01 +0000 | [diff] [blame] | 18 | #include "common/Log.h" |
Corentin Wallez | d37523f | 2018-07-24 13:53:51 +0200 | [diff] [blame] | 19 | #include "dawn_native/BindGroupLayout.h" |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 20 | #include "dawn_native/Device.h" |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 21 | #include "dawn_native/Pipeline.h" |
Corentin Wallez | d37523f | 2018-07-24 13:53:51 +0200 | [diff] [blame] | 22 | #include "dawn_native/opengl/Forward.h" |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 23 | #include "dawn_native/opengl/OpenGLFunctions.h" |
Corentin Wallez | d37523f | 2018-07-24 13:53:51 +0200 | [diff] [blame] | 24 | #include "dawn_native/opengl/PipelineLayoutGL.h" |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 25 | #include "dawn_native/opengl/SamplerGL.h" |
Corentin Wallez | d37523f | 2018-07-24 13:53:51 +0200 | [diff] [blame] | 26 | #include "dawn_native/opengl/ShaderModuleGL.h" |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 27 | |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 28 | #include <set> |
| 29 | |
Corentin Wallez | 49a65d0 | 2018-07-24 16:45:45 +0200 | [diff] [blame] | 30 | namespace dawn_native { namespace opengl { |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 31 | |
| 32 | namespace { |
| 33 | |
Corentin Wallez | b9b088f | 2019-08-27 08:42:29 +0000 | [diff] [blame] | 34 | GLenum GLShaderType(SingleShaderStage stage) { |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 35 | switch (stage) { |
Corentin Wallez | b9b088f | 2019-08-27 08:42:29 +0000 | [diff] [blame] | 36 | case SingleShaderStage::Vertex: |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 37 | return GL_VERTEX_SHADER; |
Corentin Wallez | b9b088f | 2019-08-27 08:42:29 +0000 | [diff] [blame] | 38 | case SingleShaderStage::Fragment: |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 39 | return GL_FRAGMENT_SHADER; |
Corentin Wallez | b9b088f | 2019-08-27 08:42:29 +0000 | [diff] [blame] | 40 | case SingleShaderStage::Compute: |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 41 | return GL_COMPUTE_SHADER; |
| 42 | } |
| 43 | } |
| 44 | |
Corentin Wallez | c7807ab | 2017-11-24 14:16:15 -0500 | [diff] [blame] | 45 | } // namespace |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 46 | |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 47 | PipelineGL::PipelineGL() = default; |
| 48 | PipelineGL::~PipelineGL() = default; |
Corentin Wallez | 8e335a5 | 2018-08-27 23:12:56 +0200 | [diff] [blame] | 49 | |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 50 | void PipelineGL::Initialize(const OpenGLFunctions& gl, |
| 51 | const PipelineLayout* layout, |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 52 | const PerStage<ProgrammableStage>& stages) { |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 53 | auto CreateShader = [](const OpenGLFunctions& gl, GLenum type, |
| 54 | const char* source) -> GLuint { |
| 55 | GLuint shader = gl.CreateShader(type); |
| 56 | gl.ShaderSource(shader, 1, &source, nullptr); |
| 57 | gl.CompileShader(shader); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 58 | |
| 59 | GLint compileStatus = GL_FALSE; |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 60 | gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 61 | if (compileStatus == GL_FALSE) { |
| 62 | GLint infoLogLength = 0; |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 63 | gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 64 | |
| 65 | if (infoLogLength > 1) { |
| 66 | std::vector<char> buffer(infoLogLength); |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 67 | gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]); |
Corentin Wallez | dc3317d | 2019-12-06 18:21:39 +0000 | [diff] [blame] | 68 | dawn::ErrorLog() << source << "\nProgram compilation failed:\n" |
| 69 | << buffer.data(); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 70 | } |
| 71 | } |
| 72 | return shader; |
| 73 | }; |
| 74 | |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 75 | mProgram = gl.CreateProgram(); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 76 | |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 77 | // Compute the set of active stages. |
Corentin Wallez | 1f6c8c4 | 2019-10-23 11:57:41 +0000 | [diff] [blame] | 78 | wgpu::ShaderStage activeStages = wgpu::ShaderStage::None; |
Corentin Wallez | b9b088f | 2019-08-27 08:42:29 +0000 | [diff] [blame] | 79 | for (SingleShaderStage stage : IterateStages(kAllStages)) { |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 80 | if (stages[stage].module != nullptr) { |
Corentin Wallez | 8e335a5 | 2018-08-27 23:12:56 +0200 | [diff] [blame] | 81 | activeStages |= StageBit(stage); |
| 82 | } |
| 83 | } |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 84 | |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 85 | // Create an OpenGL shader for each stage and gather the list of combined samplers. |
| 86 | PerStage<CombinedSamplerInfo> combinedSamplers; |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 87 | bool needsDummySampler = false; |
Corentin Wallez | b9b088f | 2019-08-27 08:42:29 +0000 | [diff] [blame] | 88 | for (SingleShaderStage stage : IterateStages(activeStages)) { |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 89 | const ShaderModule* module = ToBackend(stages[stage].module.Get()); |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 90 | std::string glsl = |
| 91 | module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage, |
| 92 | &combinedSamplers[stage], layout, &needsDummySampler); |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 93 | GLuint shader = CreateShader(gl, GLShaderType(stage), glsl.c_str()); |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 94 | gl.AttachShader(mProgram, shader); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 95 | } |
| 96 | |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 97 | if (needsDummySampler) { |
| 98 | SamplerDescriptor desc = {}; |
| 99 | ASSERT(desc.minFilter == wgpu::FilterMode::Nearest); |
| 100 | ASSERT(desc.magFilter == wgpu::FilterMode::Nearest); |
| 101 | ASSERT(desc.mipmapFilter == wgpu::FilterMode::Nearest); |
Corentin Wallez | 50f9958 | 2021-03-31 18:36:32 +0000 | [diff] [blame] | 102 | mDummySampler = |
| 103 | ToBackend(layout->GetDevice()->GetOrCreateSampler(&desc).AcquireSuccess()); |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 104 | } |
| 105 | |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 106 | // Link all the shaders together. |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 107 | gl.LinkProgram(mProgram); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 108 | |
| 109 | GLint linkStatus = GL_FALSE; |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 110 | gl.GetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 111 | if (linkStatus == GL_FALSE) { |
| 112 | GLint infoLogLength = 0; |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 113 | gl.GetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &infoLogLength); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 114 | |
| 115 | if (infoLogLength > 1) { |
| 116 | std::vector<char> buffer(infoLogLength); |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 117 | gl.GetProgramInfoLog(mProgram, infoLogLength, nullptr, &buffer[0]); |
Corentin Wallez | dc3317d | 2019-12-06 18:21:39 +0000 | [diff] [blame] | 118 | dawn::ErrorLog() << "Program link failed:\n" << buffer.data(); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 119 | } |
| 120 | } |
| 121 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 122 | // Compute links between stages for combined samplers, then bind them to texture units |
Corentin Wallez | 28efed1 | 2020-09-09 22:51:37 +0000 | [diff] [blame] | 123 | gl.UseProgram(mProgram); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 124 | const auto& indices = layout->GetBindingIndexInfo(); |
| 125 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 126 | std::set<CombinedSampler> combinedSamplersSet; |
| 127 | for (SingleShaderStage stage : IterateStages(activeStages)) { |
| 128 | for (const CombinedSampler& combined : combinedSamplers[stage]) { |
| 129 | combinedSamplersSet.insert(combined); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 130 | } |
| 131 | } |
| 132 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 133 | mUnitsForSamplers.resize(layout->GetNumSamplers()); |
| 134 | mUnitsForTextures.resize(layout->GetNumSampledTextures()); |
| 135 | |
| 136 | GLuint textureUnit = layout->GetTextureUnitsUsed(); |
| 137 | for (const auto& combined : combinedSamplersSet) { |
| 138 | const std::string& name = combined.GetName(); |
| 139 | GLint location = gl.GetUniformLocation(mProgram, name.c_str()); |
| 140 | |
| 141 | if (location == -1) { |
| 142 | continue; |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 143 | } |
| 144 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 145 | gl.Uniform1i(location, textureUnit); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 146 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 147 | bool shouldUseFiltering; |
| 148 | { |
| 149 | const BindGroupLayoutBase* bgl = |
| 150 | layout->GetBindGroupLayout(combined.textureLocation.group); |
| 151 | BindingIndex bindingIndex = bgl->GetBindingIndex(combined.textureLocation.binding); |
Corentin Wallez | 9dffe11 | 2019-07-22 09:24:51 +0000 | [diff] [blame] | 152 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 153 | GLuint textureIndex = indices[combined.textureLocation.group][bindingIndex]; |
| 154 | mUnitsForTextures[textureIndex].push_back(textureUnit); |
Corentin Wallez | 9dffe11 | 2019-07-22 09:24:51 +0000 | [diff] [blame] | 155 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 156 | shouldUseFiltering = bgl->GetBindingInfo(bindingIndex).texture.sampleType == |
| 157 | wgpu::TextureSampleType::Float; |
| 158 | } |
| 159 | { |
| 160 | if (combined.useDummySampler) { |
| 161 | mDummySamplerUnits.push_back(textureUnit); |
| 162 | } else { |
Austin Eng | 7a4685f | 2020-06-17 22:35:19 +0000 | [diff] [blame] | 163 | const BindGroupLayoutBase* bgl = |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 164 | layout->GetBindGroupLayout(combined.samplerLocation.group); |
Austin Eng | 7a4685f | 2020-06-17 22:35:19 +0000 | [diff] [blame] | 165 | BindingIndex bindingIndex = |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 166 | bgl->GetBindingIndex(combined.samplerLocation.binding); |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 167 | |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 168 | GLuint samplerIndex = indices[combined.samplerLocation.group][bindingIndex]; |
| 169 | mUnitsForSamplers[samplerIndex].push_back({textureUnit, shouldUseFiltering}); |
Austin Eng | 7a4685f | 2020-06-17 22:35:19 +0000 | [diff] [blame] | 170 | } |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 171 | } |
Corentin Wallez | db03566 | 2021-05-19 18:29:37 +0000 | [diff] [blame] | 172 | |
| 173 | textureUnit++; |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 174 | } |
| 175 | } |
| 176 | |
Corentin Wallez | ba9f3a8 | 2019-08-21 13:01:23 +0000 | [diff] [blame] | 177 | const std::vector<PipelineGL::SamplerUnit>& PipelineGL::GetTextureUnitsForSampler( |
| 178 | GLuint index) const { |
Corentin Wallez | 7ee1610 | 2017-11-23 11:24:20 -0800 | [diff] [blame] | 179 | ASSERT(index < mUnitsForSamplers.size()); |
| 180 | return mUnitsForSamplers[index]; |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 181 | } |
| 182 | |
Jiawei Shao | c72ab8c | 2018-10-29 09:07:25 +0000 | [diff] [blame] | 183 | const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTextureView(GLuint index) const { |
Austin Eng | 8f9523e | 2020-06-19 16:21:33 +0000 | [diff] [blame] | 184 | ASSERT(index < mUnitsForTextures.size()); |
Corentin Wallez | 7ee1610 | 2017-11-23 11:24:20 -0800 | [diff] [blame] | 185 | return mUnitsForTextures[index]; |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 186 | } |
| 187 | |
Corentin Wallez | b085eec | 2017-07-14 14:04:52 -0400 | [diff] [blame] | 188 | GLuint PipelineGL::GetProgramHandle() const { |
Corentin Wallez | 7ee1610 | 2017-11-23 11:24:20 -0800 | [diff] [blame] | 189 | return mProgram; |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 190 | } |
| 191 | |
Corentin Wallez | df69f24 | 2019-06-13 10:22:32 +0000 | [diff] [blame] | 192 | void PipelineGL::ApplyNow(const OpenGLFunctions& gl) { |
| 193 | gl.UseProgram(mProgram); |
Austin Eng | 2395ff5 | 2020-12-02 16:51:19 +0000 | [diff] [blame] | 194 | for (GLuint unit : mDummySamplerUnits) { |
| 195 | ASSERT(mDummySampler.Get() != nullptr); |
| 196 | gl.BindSampler(unit, mDummySampler->GetNonFilteringHandle()); |
| 197 | } |
Austin Eng | 376f1c6 | 2017-05-30 20:03:44 -0400 | [diff] [blame] | 198 | } |
| 199 | |
Corentin Wallez | 49a65d0 | 2018-07-24 16:45:45 +0200 | [diff] [blame] | 200 | }} // namespace dawn_native::opengl |