• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Dawn Authors
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 
15 #include "dawn_native/opengl/RenderPipelineGL.h"
16 
17 #include "dawn_native/opengl/DeviceGL.h"
18 #include "dawn_native/opengl/Forward.h"
19 #include "dawn_native/opengl/PersistentPipelineStateGL.h"
20 #include "dawn_native/opengl/UtilsGL.h"
21 
22 namespace dawn_native { namespace opengl {
23 
24     namespace {
25 
GLPrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology)26         GLenum GLPrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology) {
27             switch (primitiveTopology) {
28                 case wgpu::PrimitiveTopology::PointList:
29                     return GL_POINTS;
30                 case wgpu::PrimitiveTopology::LineList:
31                     return GL_LINES;
32                 case wgpu::PrimitiveTopology::LineStrip:
33                     return GL_LINE_STRIP;
34                 case wgpu::PrimitiveTopology::TriangleList:
35                     return GL_TRIANGLES;
36                 case wgpu::PrimitiveTopology::TriangleStrip:
37                     return GL_TRIANGLE_STRIP;
38             }
39             UNREACHABLE();
40         }
41 
ApplyFrontFaceAndCulling(const OpenGLFunctions & gl,wgpu::FrontFace face,wgpu::CullMode mode)42         void ApplyFrontFaceAndCulling(const OpenGLFunctions& gl,
43                                       wgpu::FrontFace face,
44                                       wgpu::CullMode mode) {
45             // Note that we invert winding direction in OpenGL. Because Y axis is up in OpenGL,
46             // which is different from WebGPU and other backends (Y axis is down).
47             GLenum direction = (face == wgpu::FrontFace::CCW) ? GL_CW : GL_CCW;
48             gl.FrontFace(direction);
49 
50             if (mode == wgpu::CullMode::None) {
51                 gl.Disable(GL_CULL_FACE);
52             } else {
53                 gl.Enable(GL_CULL_FACE);
54 
55                 GLenum cullMode = (mode == wgpu::CullMode::Front) ? GL_FRONT : GL_BACK;
56                 gl.CullFace(cullMode);
57             }
58         }
59 
GLBlendFactor(wgpu::BlendFactor factor,bool alpha)60         GLenum GLBlendFactor(wgpu::BlendFactor factor, bool alpha) {
61             switch (factor) {
62                 case wgpu::BlendFactor::Zero:
63                     return GL_ZERO;
64                 case wgpu::BlendFactor::One:
65                     return GL_ONE;
66                 case wgpu::BlendFactor::Src:
67                     return GL_SRC_COLOR;
68                 case wgpu::BlendFactor::OneMinusSrc:
69                     return GL_ONE_MINUS_SRC_COLOR;
70                 case wgpu::BlendFactor::SrcAlpha:
71                     return GL_SRC_ALPHA;
72                 case wgpu::BlendFactor::OneMinusSrcAlpha:
73                     return GL_ONE_MINUS_SRC_ALPHA;
74                 case wgpu::BlendFactor::Dst:
75                     return GL_DST_COLOR;
76                 case wgpu::BlendFactor::OneMinusDst:
77                     return GL_ONE_MINUS_DST_COLOR;
78                 case wgpu::BlendFactor::DstAlpha:
79                     return GL_DST_ALPHA;
80                 case wgpu::BlendFactor::OneMinusDstAlpha:
81                     return GL_ONE_MINUS_DST_ALPHA;
82                 case wgpu::BlendFactor::SrcAlphaSaturated:
83                     return GL_SRC_ALPHA_SATURATE;
84                 case wgpu::BlendFactor::Constant:
85                     return alpha ? GL_CONSTANT_ALPHA : GL_CONSTANT_COLOR;
86                 case wgpu::BlendFactor::OneMinusConstant:
87                     return alpha ? GL_ONE_MINUS_CONSTANT_ALPHA : GL_ONE_MINUS_CONSTANT_COLOR;
88             }
89             UNREACHABLE();
90         }
91 
GLBlendMode(wgpu::BlendOperation operation)92         GLenum GLBlendMode(wgpu::BlendOperation operation) {
93             switch (operation) {
94                 case wgpu::BlendOperation::Add:
95                     return GL_FUNC_ADD;
96                 case wgpu::BlendOperation::Subtract:
97                     return GL_FUNC_SUBTRACT;
98                 case wgpu::BlendOperation::ReverseSubtract:
99                     return GL_FUNC_REVERSE_SUBTRACT;
100                 case wgpu::BlendOperation::Min:
101                     return GL_MIN;
102                 case wgpu::BlendOperation::Max:
103                     return GL_MAX;
104             }
105             UNREACHABLE();
106         }
107 
ApplyColorState(const OpenGLFunctions & gl,ColorAttachmentIndex attachment,const ColorTargetState * state)108         void ApplyColorState(const OpenGLFunctions& gl,
109                              ColorAttachmentIndex attachment,
110                              const ColorTargetState* state) {
111             GLuint colorBuffer = static_cast<GLuint>(static_cast<uint8_t>(attachment));
112             if (state->blend != nullptr) {
113                 gl.Enablei(GL_BLEND, colorBuffer);
114                 gl.BlendEquationSeparatei(colorBuffer, GLBlendMode(state->blend->color.operation),
115                                           GLBlendMode(state->blend->alpha.operation));
116                 gl.BlendFuncSeparatei(colorBuffer,
117                                       GLBlendFactor(state->blend->color.srcFactor, false),
118                                       GLBlendFactor(state->blend->color.dstFactor, false),
119                                       GLBlendFactor(state->blend->alpha.srcFactor, true),
120                                       GLBlendFactor(state->blend->alpha.dstFactor, true));
121             } else {
122                 gl.Disablei(GL_BLEND, colorBuffer);
123             }
124             gl.ColorMaski(colorBuffer, state->writeMask & wgpu::ColorWriteMask::Red,
125                           state->writeMask & wgpu::ColorWriteMask::Green,
126                           state->writeMask & wgpu::ColorWriteMask::Blue,
127                           state->writeMask & wgpu::ColorWriteMask::Alpha);
128         }
129 
ApplyColorState(const OpenGLFunctions & gl,const ColorTargetState * state)130         void ApplyColorState(const OpenGLFunctions& gl, const ColorTargetState* state) {
131             if (state->blend != nullptr) {
132                 gl.Enable(GL_BLEND);
133                 gl.BlendEquationSeparate(GLBlendMode(state->blend->color.operation),
134                                          GLBlendMode(state->blend->alpha.operation));
135                 gl.BlendFuncSeparate(GLBlendFactor(state->blend->color.srcFactor, false),
136                                      GLBlendFactor(state->blend->color.dstFactor, false),
137                                      GLBlendFactor(state->blend->alpha.srcFactor, true),
138                                      GLBlendFactor(state->blend->alpha.dstFactor, true));
139             } else {
140                 gl.Disable(GL_BLEND);
141             }
142             gl.ColorMask(state->writeMask & wgpu::ColorWriteMask::Red,
143                          state->writeMask & wgpu::ColorWriteMask::Green,
144                          state->writeMask & wgpu::ColorWriteMask::Blue,
145                          state->writeMask & wgpu::ColorWriteMask::Alpha);
146         }
147 
Equal(const BlendComponent & lhs,const BlendComponent & rhs)148         bool Equal(const BlendComponent& lhs, const BlendComponent& rhs) {
149             return lhs.operation == rhs.operation && lhs.srcFactor == rhs.srcFactor &&
150                    lhs.dstFactor == rhs.dstFactor;
151         }
152 
OpenGLStencilOperation(wgpu::StencilOperation stencilOperation)153         GLuint OpenGLStencilOperation(wgpu::StencilOperation stencilOperation) {
154             switch (stencilOperation) {
155                 case wgpu::StencilOperation::Keep:
156                     return GL_KEEP;
157                 case wgpu::StencilOperation::Zero:
158                     return GL_ZERO;
159                 case wgpu::StencilOperation::Replace:
160                     return GL_REPLACE;
161                 case wgpu::StencilOperation::Invert:
162                     return GL_INVERT;
163                 case wgpu::StencilOperation::IncrementClamp:
164                     return GL_INCR;
165                 case wgpu::StencilOperation::DecrementClamp:
166                     return GL_DECR;
167                 case wgpu::StencilOperation::IncrementWrap:
168                     return GL_INCR_WRAP;
169                 case wgpu::StencilOperation::DecrementWrap:
170                     return GL_DECR_WRAP;
171             }
172             UNREACHABLE();
173         }
174 
ApplyDepthStencilState(const OpenGLFunctions & gl,const DepthStencilState * descriptor,PersistentPipelineState * persistentPipelineState)175         void ApplyDepthStencilState(const OpenGLFunctions& gl,
176                                     const DepthStencilState* descriptor,
177                                     PersistentPipelineState* persistentPipelineState) {
178             // Depth writes only occur if depth is enabled
179             if (descriptor->depthCompare == wgpu::CompareFunction::Always &&
180                 !descriptor->depthWriteEnabled) {
181                 gl.Disable(GL_DEPTH_TEST);
182             } else {
183                 gl.Enable(GL_DEPTH_TEST);
184             }
185 
186             if (descriptor->depthWriteEnabled) {
187                 gl.DepthMask(GL_TRUE);
188             } else {
189                 gl.DepthMask(GL_FALSE);
190             }
191 
192             gl.DepthFunc(ToOpenGLCompareFunction(descriptor->depthCompare));
193 
194             if (StencilTestEnabled(descriptor)) {
195                 gl.Enable(GL_STENCIL_TEST);
196             } else {
197                 gl.Disable(GL_STENCIL_TEST);
198             }
199 
200             GLenum backCompareFunction = ToOpenGLCompareFunction(descriptor->stencilBack.compare);
201             GLenum frontCompareFunction = ToOpenGLCompareFunction(descriptor->stencilFront.compare);
202             persistentPipelineState->SetStencilFuncsAndMask(
203                 gl, backCompareFunction, frontCompareFunction, descriptor->stencilReadMask);
204 
205             gl.StencilOpSeparate(GL_BACK, OpenGLStencilOperation(descriptor->stencilBack.failOp),
206                                  OpenGLStencilOperation(descriptor->stencilBack.depthFailOp),
207                                  OpenGLStencilOperation(descriptor->stencilBack.passOp));
208             gl.StencilOpSeparate(GL_FRONT, OpenGLStencilOperation(descriptor->stencilFront.failOp),
209                                  OpenGLStencilOperation(descriptor->stencilFront.depthFailOp),
210                                  OpenGLStencilOperation(descriptor->stencilFront.passOp));
211 
212             gl.StencilMask(descriptor->stencilWriteMask);
213         }
214 
215     }  // anonymous namespace
216 
217     // static
CreateUninitialized(Device * device,const RenderPipelineDescriptor * descriptor)218     Ref<RenderPipeline> RenderPipeline::CreateUninitialized(
219         Device* device,
220         const RenderPipelineDescriptor* descriptor) {
221         return AcquireRef(new RenderPipeline(device, descriptor));
222     }
223 
RenderPipeline(Device * device,const RenderPipelineDescriptor * descriptor)224     RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
225         : RenderPipelineBase(device, descriptor),
226           mVertexArrayObject(0),
227           mGlPrimitiveTopology(GLPrimitiveTopology(GetPrimitiveTopology())) {
228     }
229 
Initialize()230     MaybeError RenderPipeline::Initialize() {
231         DAWN_TRY(
232             InitializeBase(ToBackend(GetDevice())->gl, ToBackend(GetLayout()), GetAllStages()));
233         CreateVAOForVertexState();
234         return {};
235     }
236 
237     RenderPipeline::~RenderPipeline() = default;
238 
DestroyImpl()239     void RenderPipeline::DestroyImpl() {
240         RenderPipelineBase::DestroyImpl();
241         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
242         gl.DeleteVertexArrays(1, &mVertexArrayObject);
243         gl.BindVertexArray(0);
244         DeleteProgram(gl);
245     }
246 
GetGLPrimitiveTopology() const247     GLenum RenderPipeline::GetGLPrimitiveTopology() const {
248         return mGlPrimitiveTopology;
249     }
250 
251     ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes>
GetAttributesUsingVertexBuffer(VertexBufferSlot slot) const252     RenderPipeline::GetAttributesUsingVertexBuffer(VertexBufferSlot slot) const {
253         ASSERT(!IsError());
254         return mAttributesUsingVertexBuffer[slot];
255     }
256 
CreateVAOForVertexState()257     void RenderPipeline::CreateVAOForVertexState() {
258         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
259 
260         gl.GenVertexArrays(1, &mVertexArrayObject);
261         gl.BindVertexArray(mVertexArrayObject);
262 
263         for (VertexAttributeLocation location : IterateBitSet(GetAttributeLocationsUsed())) {
264             const auto& attribute = GetAttribute(location);
265             GLuint glAttrib = static_cast<GLuint>(static_cast<uint8_t>(location));
266             gl.EnableVertexAttribArray(glAttrib);
267 
268             mAttributesUsingVertexBuffer[attribute.vertexBufferSlot][location] = true;
269             const VertexBufferInfo& vertexBuffer = GetVertexBuffer(attribute.vertexBufferSlot);
270 
271             if (vertexBuffer.arrayStride == 0) {
272                 // Emulate a stride of zero (constant vertex attribute) by
273                 // setting the attribute instance divisor to a huge number.
274                 gl.VertexAttribDivisor(glAttrib, 0xffffffff);
275             } else {
276                 switch (vertexBuffer.stepMode) {
277                     case wgpu::VertexStepMode::Vertex:
278                         break;
279                     case wgpu::VertexStepMode::Instance:
280                         gl.VertexAttribDivisor(glAttrib, 1);
281                         break;
282                 }
283             }
284         }
285     }
286 
ApplyNow(PersistentPipelineState & persistentPipelineState)287     void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) {
288         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
289         PipelineGL::ApplyNow(gl);
290 
291         ASSERT(mVertexArrayObject);
292         gl.BindVertexArray(mVertexArrayObject);
293 
294         ApplyFrontFaceAndCulling(gl, GetFrontFace(), GetCullMode());
295 
296         ApplyDepthStencilState(gl, GetDepthStencilState(), &persistentPipelineState);
297 
298         gl.SampleMaski(0, GetSampleMask());
299         if (IsAlphaToCoverageEnabled()) {
300             gl.Enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
301         } else {
302             gl.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE);
303         }
304 
305         if (IsDepthBiasEnabled()) {
306             gl.Enable(GL_POLYGON_OFFSET_FILL);
307             float depthBias = GetDepthBias();
308             float slopeScale = GetDepthBiasSlopeScale();
309             if (gl.PolygonOffsetClamp != nullptr) {
310                 gl.PolygonOffsetClamp(slopeScale, depthBias, GetDepthBiasClamp());
311             } else {
312                 gl.PolygonOffset(slopeScale, depthBias);
313             }
314         } else {
315             gl.Disable(GL_POLYGON_OFFSET_FILL);
316         }
317 
318         if (!GetDevice()->IsToggleEnabled(Toggle::DisableIndexedDrawBuffers)) {
319             for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
320                 ApplyColorState(gl, attachmentSlot, GetColorTargetState(attachmentSlot));
321             }
322         } else {
323             const ColorTargetState* prevDescriptor = nullptr;
324             for (ColorAttachmentIndex attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
325                 const ColorTargetState* descriptor = GetColorTargetState(attachmentSlot);
326                 if (!prevDescriptor) {
327                     ApplyColorState(gl, descriptor);
328                     prevDescriptor = descriptor;
329                 } else if ((descriptor->blend == nullptr) != (prevDescriptor->blend == nullptr)) {
330                     // TODO(crbug.com/dawn/582): GLES < 3.2 does not support different blend states
331                     // per color target. Add validation to prevent this as it is not.
332                     ASSERT(false);
333                 } else if (descriptor->blend != nullptr) {
334                     if (!Equal(descriptor->blend->alpha, prevDescriptor->blend->alpha) ||
335                         !Equal(descriptor->blend->color, prevDescriptor->blend->color) ||
336                         descriptor->writeMask != prevDescriptor->writeMask) {
337                         // TODO(crbug.com/dawn/582)
338                         ASSERT(false);
339                     }
340                 }
341             }
342         }
343     }
344 
345 }}  // namespace dawn_native::opengl
346