blob: 01100254b4b8805028eb0b9b2c55faeb99e51d64 [file] [log] [blame]
Corentin Wallez4a9ef4e2018-07-18 11:40:26 +02001// Copyright 2017 The Dawn Authors
Austin Eng376f1c62017-05-30 20:03:44 -04002//
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 Wallezd37523f2018-07-24 13:53:51 +020015#include "dawn_native/opengl/PipelineGL.h"
Austin Eng376f1c62017-05-30 20:03:44 -040016
Kai Ninomiya311e2a42018-06-29 18:22:02 -070017#include "common/BitSetIterator.h"
Corentin Wallez95586ff2019-12-05 11:13:01 +000018#include "common/Log.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020019#include "dawn_native/BindGroupLayout.h"
Austin Eng2395ff52020-12-02 16:51:19 +000020#include "dawn_native/Device.h"
Corentin Wallez28efed12020-09-09 22:51:37 +000021#include "dawn_native/Pipeline.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020022#include "dawn_native/opengl/Forward.h"
Corentin Wallezdf69f242019-06-13 10:22:32 +000023#include "dawn_native/opengl/OpenGLFunctions.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020024#include "dawn_native/opengl/PipelineLayoutGL.h"
Austin Eng2395ff52020-12-02 16:51:19 +000025#include "dawn_native/opengl/SamplerGL.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020026#include "dawn_native/opengl/ShaderModuleGL.h"
Austin Eng376f1c62017-05-30 20:03:44 -040027
Austin Eng376f1c62017-05-30 20:03:44 -040028#include <set>
29
Corentin Wallez49a65d02018-07-24 16:45:45 +020030namespace dawn_native { namespace opengl {
Austin Eng376f1c62017-05-30 20:03:44 -040031
32 namespace {
33
Corentin Wallezb9b088f2019-08-27 08:42:29 +000034 GLenum GLShaderType(SingleShaderStage stage) {
Austin Eng376f1c62017-05-30 20:03:44 -040035 switch (stage) {
Corentin Wallezb9b088f2019-08-27 08:42:29 +000036 case SingleShaderStage::Vertex:
Austin Eng376f1c62017-05-30 20:03:44 -040037 return GL_VERTEX_SHADER;
Corentin Wallezb9b088f2019-08-27 08:42:29 +000038 case SingleShaderStage::Fragment:
Austin Eng376f1c62017-05-30 20:03:44 -040039 return GL_FRAGMENT_SHADER;
Corentin Wallezb9b088f2019-08-27 08:42:29 +000040 case SingleShaderStage::Compute:
Austin Eng376f1c62017-05-30 20:03:44 -040041 return GL_COMPUTE_SHADER;
42 }
43 }
44
Corentin Wallezc7807ab2017-11-24 14:16:15 -050045 } // namespace
Austin Eng376f1c62017-05-30 20:03:44 -040046
Austin Eng2395ff52020-12-02 16:51:19 +000047 PipelineGL::PipelineGL() = default;
48 PipelineGL::~PipelineGL() = default;
Corentin Wallez8e335a52018-08-27 23:12:56 +020049
Corentin Wallezdf69f242019-06-13 10:22:32 +000050 void PipelineGL::Initialize(const OpenGLFunctions& gl,
51 const PipelineLayout* layout,
Corentin Wallez28efed12020-09-09 22:51:37 +000052 const PerStage<ProgrammableStage>& stages) {
Corentin Wallezdf69f242019-06-13 10:22:32 +000053 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 Eng376f1c62017-05-30 20:03:44 -040058
59 GLint compileStatus = GL_FALSE;
Corentin Wallezdf69f242019-06-13 10:22:32 +000060 gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
Austin Eng376f1c62017-05-30 20:03:44 -040061 if (compileStatus == GL_FALSE) {
62 GLint infoLogLength = 0;
Corentin Wallezdf69f242019-06-13 10:22:32 +000063 gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
Austin Eng376f1c62017-05-30 20:03:44 -040064
65 if (infoLogLength > 1) {
66 std::vector<char> buffer(infoLogLength);
Corentin Wallezdf69f242019-06-13 10:22:32 +000067 gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
Corentin Wallezdc3317d2019-12-06 18:21:39 +000068 dawn::ErrorLog() << source << "\nProgram compilation failed:\n"
69 << buffer.data();
Austin Eng376f1c62017-05-30 20:03:44 -040070 }
71 }
72 return shader;
73 };
74
Corentin Wallezdf69f242019-06-13 10:22:32 +000075 mProgram = gl.CreateProgram();
Austin Eng376f1c62017-05-30 20:03:44 -040076
Corentin Wallez28efed12020-09-09 22:51:37 +000077 // Compute the set of active stages.
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000078 wgpu::ShaderStage activeStages = wgpu::ShaderStage::None;
Corentin Wallezb9b088f2019-08-27 08:42:29 +000079 for (SingleShaderStage stage : IterateStages(kAllStages)) {
Corentin Wallez28efed12020-09-09 22:51:37 +000080 if (stages[stage].module != nullptr) {
Corentin Wallez8e335a52018-08-27 23:12:56 +020081 activeStages |= StageBit(stage);
82 }
83 }
Austin Eng376f1c62017-05-30 20:03:44 -040084
Corentin Wallez28efed12020-09-09 22:51:37 +000085 // Create an OpenGL shader for each stage and gather the list of combined samplers.
86 PerStage<CombinedSamplerInfo> combinedSamplers;
Austin Eng2395ff52020-12-02 16:51:19 +000087 bool needsDummySampler = false;
Corentin Wallezb9b088f2019-08-27 08:42:29 +000088 for (SingleShaderStage stage : IterateStages(activeStages)) {
Corentin Wallez28efed12020-09-09 22:51:37 +000089 const ShaderModule* module = ToBackend(stages[stage].module.Get());
Austin Eng2395ff52020-12-02 16:51:19 +000090 std::string glsl =
91 module->TranslateToGLSL(stages[stage].entryPoint.c_str(), stage,
92 &combinedSamplers[stage], layout, &needsDummySampler);
Corentin Wallez28efed12020-09-09 22:51:37 +000093 GLuint shader = CreateShader(gl, GLShaderType(stage), glsl.c_str());
Corentin Wallezdf69f242019-06-13 10:22:32 +000094 gl.AttachShader(mProgram, shader);
Austin Eng376f1c62017-05-30 20:03:44 -040095 }
96
Austin Eng2395ff52020-12-02 16:51:19 +000097 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 Wallez50f99582021-03-31 18:36:32 +0000102 mDummySampler =
103 ToBackend(layout->GetDevice()->GetOrCreateSampler(&desc).AcquireSuccess());
Austin Eng2395ff52020-12-02 16:51:19 +0000104 }
105
Corentin Wallez28efed12020-09-09 22:51:37 +0000106 // Link all the shaders together.
Corentin Wallezdf69f242019-06-13 10:22:32 +0000107 gl.LinkProgram(mProgram);
Austin Eng376f1c62017-05-30 20:03:44 -0400108
109 GLint linkStatus = GL_FALSE;
Corentin Wallezdf69f242019-06-13 10:22:32 +0000110 gl.GetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
Austin Eng376f1c62017-05-30 20:03:44 -0400111 if (linkStatus == GL_FALSE) {
112 GLint infoLogLength = 0;
Corentin Wallezdf69f242019-06-13 10:22:32 +0000113 gl.GetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
Austin Eng376f1c62017-05-30 20:03:44 -0400114
115 if (infoLogLength > 1) {
116 std::vector<char> buffer(infoLogLength);
Corentin Wallezdf69f242019-06-13 10:22:32 +0000117 gl.GetProgramInfoLog(mProgram, infoLogLength, nullptr, &buffer[0]);
Corentin Wallezdc3317d2019-12-06 18:21:39 +0000118 dawn::ErrorLog() << "Program link failed:\n" << buffer.data();
Austin Eng376f1c62017-05-30 20:03:44 -0400119 }
120 }
121
Corentin Wallezdb035662021-05-19 18:29:37 +0000122 // Compute links between stages for combined samplers, then bind them to texture units
Corentin Wallez28efed12020-09-09 22:51:37 +0000123 gl.UseProgram(mProgram);
Austin Eng376f1c62017-05-30 20:03:44 -0400124 const auto& indices = layout->GetBindingIndexInfo();
125
Corentin Wallezdb035662021-05-19 18:29:37 +0000126 std::set<CombinedSampler> combinedSamplersSet;
127 for (SingleShaderStage stage : IterateStages(activeStages)) {
128 for (const CombinedSampler& combined : combinedSamplers[stage]) {
129 combinedSamplersSet.insert(combined);
Austin Eng376f1c62017-05-30 20:03:44 -0400130 }
131 }
132
Corentin Wallezdb035662021-05-19 18:29:37 +0000133 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 Eng376f1c62017-05-30 20:03:44 -0400143 }
144
Corentin Wallezdb035662021-05-19 18:29:37 +0000145 gl.Uniform1i(location, textureUnit);
Austin Eng376f1c62017-05-30 20:03:44 -0400146
Corentin Wallezdb035662021-05-19 18:29:37 +0000147 bool shouldUseFiltering;
148 {
149 const BindGroupLayoutBase* bgl =
150 layout->GetBindGroupLayout(combined.textureLocation.group);
151 BindingIndex bindingIndex = bgl->GetBindingIndex(combined.textureLocation.binding);
Corentin Wallez9dffe112019-07-22 09:24:51 +0000152
Corentin Wallezdb035662021-05-19 18:29:37 +0000153 GLuint textureIndex = indices[combined.textureLocation.group][bindingIndex];
154 mUnitsForTextures[textureIndex].push_back(textureUnit);
Corentin Wallez9dffe112019-07-22 09:24:51 +0000155
Corentin Wallezdb035662021-05-19 18:29:37 +0000156 shouldUseFiltering = bgl->GetBindingInfo(bindingIndex).texture.sampleType ==
157 wgpu::TextureSampleType::Float;
158 }
159 {
160 if (combined.useDummySampler) {
161 mDummySamplerUnits.push_back(textureUnit);
162 } else {
Austin Eng7a4685f2020-06-17 22:35:19 +0000163 const BindGroupLayoutBase* bgl =
Corentin Wallezdb035662021-05-19 18:29:37 +0000164 layout->GetBindGroupLayout(combined.samplerLocation.group);
Austin Eng7a4685f2020-06-17 22:35:19 +0000165 BindingIndex bindingIndex =
Corentin Wallezdb035662021-05-19 18:29:37 +0000166 bgl->GetBindingIndex(combined.samplerLocation.binding);
Austin Eng376f1c62017-05-30 20:03:44 -0400167
Corentin Wallezdb035662021-05-19 18:29:37 +0000168 GLuint samplerIndex = indices[combined.samplerLocation.group][bindingIndex];
169 mUnitsForSamplers[samplerIndex].push_back({textureUnit, shouldUseFiltering});
Austin Eng7a4685f2020-06-17 22:35:19 +0000170 }
Austin Eng376f1c62017-05-30 20:03:44 -0400171 }
Corentin Wallezdb035662021-05-19 18:29:37 +0000172
173 textureUnit++;
Austin Eng376f1c62017-05-30 20:03:44 -0400174 }
175 }
176
Corentin Wallezba9f3a82019-08-21 13:01:23 +0000177 const std::vector<PipelineGL::SamplerUnit>& PipelineGL::GetTextureUnitsForSampler(
178 GLuint index) const {
Corentin Wallez7ee16102017-11-23 11:24:20 -0800179 ASSERT(index < mUnitsForSamplers.size());
180 return mUnitsForSamplers[index];
Austin Eng376f1c62017-05-30 20:03:44 -0400181 }
182
Jiawei Shaoc72ab8c2018-10-29 09:07:25 +0000183 const std::vector<GLuint>& PipelineGL::GetTextureUnitsForTextureView(GLuint index) const {
Austin Eng8f9523e2020-06-19 16:21:33 +0000184 ASSERT(index < mUnitsForTextures.size());
Corentin Wallez7ee16102017-11-23 11:24:20 -0800185 return mUnitsForTextures[index];
Austin Eng376f1c62017-05-30 20:03:44 -0400186 }
187
Corentin Wallezb085eec2017-07-14 14:04:52 -0400188 GLuint PipelineGL::GetProgramHandle() const {
Corentin Wallez7ee16102017-11-23 11:24:20 -0800189 return mProgram;
Austin Eng376f1c62017-05-30 20:03:44 -0400190 }
191
Corentin Wallezdf69f242019-06-13 10:22:32 +0000192 void PipelineGL::ApplyNow(const OpenGLFunctions& gl) {
193 gl.UseProgram(mProgram);
Austin Eng2395ff52020-12-02 16:51:19 +0000194 for (GLuint unit : mDummySamplerUnits) {
195 ASSERT(mDummySampler.Get() != nullptr);
196 gl.BindSampler(unit, mDummySampler->GetNonFilteringHandle());
197 }
Austin Eng376f1c62017-05-30 20:03:44 -0400198 }
199
Corentin Wallez49a65d02018-07-24 16:45:45 +0200200}} // namespace dawn_native::opengl