Line data Source code
1 : /* Copyright (C) 2023 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "DeviceCommandContext.h"
21 :
22 : #include "ps/CLogger.h"
23 : #include "renderer/backend/gl/Buffer.h"
24 : #include "renderer/backend/gl/Device.h"
25 : #include "renderer/backend/gl/Framebuffer.h"
26 : #include "renderer/backend/gl/Mapping.h"
27 : #include "renderer/backend/gl/PipelineState.h"
28 : #include "renderer/backend/gl/ShaderProgram.h"
29 : #include "renderer/backend/gl/Texture.h"
30 :
31 : #include <algorithm>
32 : #include <cstring>
33 : #include <limits>
34 :
35 : namespace Renderer
36 : {
37 :
38 : namespace Backend
39 : {
40 :
41 : namespace GL
42 : {
43 :
44 : namespace
45 : {
46 :
47 0 : bool operator==(const SStencilOpState& lhs, const SStencilOpState& rhs)
48 : {
49 : return
50 0 : lhs.failOp == rhs.failOp &&
51 0 : lhs.passOp == rhs.passOp &&
52 0 : lhs.depthFailOp == rhs.depthFailOp &&
53 0 : lhs.compareOp == rhs.compareOp;
54 : }
55 0 : bool operator!=(const SStencilOpState& lhs, const SStencilOpState& rhs)
56 : {
57 0 : return !operator==(lhs, rhs);
58 : }
59 :
60 0 : bool operator==(
61 : const CDeviceCommandContext::Rect& lhs,
62 : const CDeviceCommandContext::Rect& rhs)
63 : {
64 : return
65 0 : lhs.x == rhs.x && lhs.y == rhs.y &&
66 0 : lhs.width == rhs.width && lhs.height == rhs.height;
67 : }
68 :
69 0 : bool operator!=(
70 : const CDeviceCommandContext::Rect& lhs,
71 : const CDeviceCommandContext::Rect& rhs)
72 : {
73 0 : return !operator==(lhs, rhs);
74 : }
75 :
76 0 : void ApplyDepthMask(const bool depthWriteEnabled)
77 : {
78 0 : glDepthMask(depthWriteEnabled ? GL_TRUE : GL_FALSE);
79 0 : }
80 :
81 0 : void ApplyColorMask(const uint8_t colorWriteMask)
82 : {
83 0 : glColorMask(
84 : (colorWriteMask & ColorWriteMask::RED) != 0 ? GL_TRUE : GL_FALSE,
85 0 : (colorWriteMask & ColorWriteMask::GREEN) != 0 ? GL_TRUE : GL_FALSE,
86 0 : (colorWriteMask & ColorWriteMask::BLUE) != 0 ? GL_TRUE : GL_FALSE,
87 0 : (colorWriteMask & ColorWriteMask::ALPHA) != 0 ? GL_TRUE : GL_FALSE);
88 0 : }
89 :
90 0 : void ApplyStencilMask(const uint32_t stencilWriteMask)
91 : {
92 0 : glStencilMask(stencilWriteMask);
93 0 : }
94 :
95 0 : GLenum BufferTypeToGLTarget(const CBuffer::Type type)
96 : {
97 0 : GLenum target = GL_ARRAY_BUFFER;
98 0 : switch (type)
99 : {
100 0 : case CBuffer::Type::VERTEX:
101 0 : target = GL_ARRAY_BUFFER;
102 0 : break;
103 0 : case CBuffer::Type::INDEX:
104 0 : target = GL_ELEMENT_ARRAY_BUFFER;
105 0 : break;
106 0 : case CBuffer::Type::UPLOAD:
107 : case CBuffer::Type::UNIFORM:
108 0 : debug_warn("Unsupported buffer type.");
109 0 : break;
110 : };
111 0 : return target;
112 : }
113 :
114 0 : void UploadDynamicBufferRegionImpl(
115 : const GLenum target, const uint32_t bufferSize,
116 : const uint32_t dataOffset, const uint32_t dataSize,
117 : const CDeviceCommandContext::UploadBufferFunction& uploadFunction)
118 : {
119 0 : ENSURE(dataOffset < dataSize);
120 : // Tell the driver that it can reallocate the whole VBO
121 0 : glBufferDataARB(target, bufferSize, nullptr, GL_DYNAMIC_DRAW);
122 0 : ogl_WarnIfError();
123 :
124 : while (true)
125 : {
126 : // (In theory, glMapBufferRange with GL_MAP_INVALIDATE_BUFFER_BIT could be used
127 : // here instead of glBufferData(..., NULL, ...) plus glMapBuffer(), but with
128 : // current Intel Windows GPU drivers (as of 2015-01) it's much faster if you do
129 : // the explicit glBufferData.)
130 0 : void* mappedData = glMapBufferARB(target, GL_WRITE_ONLY);
131 0 : if (mappedData == nullptr)
132 : {
133 : // This shouldn't happen unless we run out of virtual address space
134 0 : LOGERROR("glMapBuffer failed");
135 0 : break;
136 : }
137 :
138 0 : uploadFunction(static_cast<u8*>(mappedData) + dataOffset);
139 :
140 0 : if (glUnmapBufferARB(target) == GL_TRUE)
141 0 : break;
142 :
143 : // Unmap might fail on e.g. resolution switches, so just try again
144 : // and hope it will eventually succeed
145 0 : LOGMESSAGE("glUnmapBuffer failed, trying again...\n");
146 0 : }
147 0 : }
148 :
149 : /**
150 : * In case we don't need a framebuffer content (because of the following clear
151 : * or overwriting by a shader) we might give a hint to a driver via
152 : * glInvalidateFramebuffer.
153 : */
154 0 : void InvalidateFramebuffer(
155 : CFramebuffer* framebuffer, const bool color, const bool depthStencil)
156 : {
157 0 : GLsizei numberOfAttachments = 0;
158 : GLenum attachments[8];
159 0 : const bool isBackbuffer = framebuffer->GetHandle() == 0;
160 0 : if (color && (framebuffer->GetAttachmentMask() & GL_COLOR_BUFFER_BIT))
161 : {
162 0 : if (isBackbuffer)
163 : #if CONFIG2_GLES
164 : attachments[numberOfAttachments++] = GL_COLOR_EXT;
165 : #else
166 0 : attachments[numberOfAttachments++] = GL_COLOR;
167 : #endif
168 : else
169 0 : attachments[numberOfAttachments++] = GL_COLOR_ATTACHMENT0;
170 : }
171 0 : if (depthStencil)
172 : {
173 0 : if (isBackbuffer)
174 : {
175 0 : if (framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT)
176 : #if CONFIG2_GLES
177 : attachments[numberOfAttachments++] = GL_DEPTH_EXT;
178 : #else
179 0 : attachments[numberOfAttachments++] = GL_DEPTH;
180 : #endif
181 0 : if (framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT)
182 : #if CONFIG2_GLES
183 : attachments[numberOfAttachments++] = GL_STENCIL_EXT;
184 : #else
185 0 : attachments[numberOfAttachments++] = GL_STENCIL;
186 : #endif
187 : }
188 : else
189 : {
190 0 : if (framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT)
191 0 : attachments[numberOfAttachments++] = GL_DEPTH_ATTACHMENT;
192 0 : if (framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT)
193 0 : attachments[numberOfAttachments++] = GL_STENCIL_ATTACHMENT;
194 : }
195 : }
196 :
197 0 : if (numberOfAttachments > 0)
198 : {
199 : #if CONFIG2_GLES
200 : glDiscardFramebufferEXT(GL_FRAMEBUFFER_EXT, numberOfAttachments, attachments);
201 : #else
202 0 : glInvalidateFramebuffer(GL_FRAMEBUFFER_EXT, numberOfAttachments, attachments);
203 : #endif
204 0 : ogl_WarnIfError();
205 : }
206 0 : }
207 :
208 : } // anonymous namespace
209 :
210 : // static
211 0 : std::unique_ptr<CDeviceCommandContext> CDeviceCommandContext::Create(CDevice* device)
212 : {
213 0 : std::unique_ptr<CDeviceCommandContext> deviceCommandContext(new CDeviceCommandContext(device));
214 0 : deviceCommandContext->m_Framebuffer = device->GetCurrentBackbuffer(
215 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
216 : Renderer::Backend::AttachmentStoreOp::DONT_CARE,
217 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
218 0 : Renderer::Backend::AttachmentStoreOp::DONT_CARE)->As<CFramebuffer>();
219 0 : deviceCommandContext->ResetStates();
220 0 : return deviceCommandContext;
221 : }
222 :
223 0 : CDeviceCommandContext::CDeviceCommandContext(CDevice* device)
224 0 : : m_Device(device)
225 : {
226 0 : glActiveTexture(GL_TEXTURE0);
227 0 : glBindTexture(GL_TEXTURE_2D, 0);
228 0 : for (BindUnit& unit : m_BoundTextures)
229 : {
230 0 : unit.target = GL_TEXTURE_2D;
231 0 : unit.handle = 0;
232 : }
233 0 : for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index)
234 : {
235 0 : m_VertexAttributeFormat[index].active = false;
236 0 : m_VertexAttributeFormat[index].initialized = false;
237 0 : m_VertexAttributeFormat[index].bindingSlot = 0;
238 : }
239 :
240 0 : for (size_t index = 0; index < m_BoundBuffers.size(); ++index)
241 : {
242 0 : const CBuffer::Type type = static_cast<CBuffer::Type>(index);
243 0 : const GLenum target = BufferTypeToGLTarget(type);
244 0 : const GLuint handle = 0;
245 0 : m_BoundBuffers[index].first = target;
246 0 : m_BoundBuffers[index].second = handle;
247 : }
248 0 : }
249 :
250 : CDeviceCommandContext::~CDeviceCommandContext() = default;
251 :
252 0 : IDevice* CDeviceCommandContext::GetDevice()
253 : {
254 0 : return m_Device;
255 : }
256 :
257 0 : void CDeviceCommandContext::SetGraphicsPipelineState(
258 : const SGraphicsPipelineStateDesc& pipelineState)
259 : {
260 0 : SetGraphicsPipelineStateImpl(pipelineState, false);
261 0 : }
262 :
263 0 : void CDeviceCommandContext::SetGraphicsPipelineState(
264 : IGraphicsPipelineState* pipelineState)
265 : {
266 0 : ENSURE(pipelineState);
267 0 : SetGraphicsPipelineStateImpl(
268 : pipelineState->As<CGraphicsPipelineState>()->GetDesc(), false);
269 0 : }
270 :
271 0 : void CDeviceCommandContext::UploadTexture(
272 : ITexture* texture, const Format format,
273 : const void* data, const size_t dataSize,
274 : const uint32_t level, const uint32_t layer)
275 : {
276 0 : UploadTextureRegion(texture, format, data, dataSize,
277 : 0, 0,
278 0 : std::max(1u, texture->GetWidth() >> level),
279 0 : std::max(1u, texture->GetHeight() >> level),
280 : level, layer);
281 0 : }
282 :
283 0 : void CDeviceCommandContext::UploadTextureRegion(
284 : ITexture* destinationTexture, const Format dataFormat,
285 : const void* data, const size_t dataSize,
286 : const uint32_t xOffset, const uint32_t yOffset,
287 : const uint32_t width, const uint32_t height,
288 : const uint32_t level, const uint32_t layer)
289 : {
290 0 : ENSURE(destinationTexture);
291 0 : CTexture* texture = destinationTexture->As<CTexture>();
292 0 : ENSURE(texture->GetUsage() & Renderer::Backend::ITexture::Usage::TRANSFER_DST);
293 0 : ENSURE(width > 0 && height > 0);
294 0 : if (texture->GetType() == CTexture::Type::TEXTURE_2D)
295 : {
296 0 : ENSURE(layer == 0);
297 0 : if (texture->GetFormat() == Format::R8G8B8A8_UNORM ||
298 0 : texture->GetFormat() == Format::R8G8B8_UNORM ||
299 : #if !CONFIG2_GLES
300 0 : texture->GetFormat() == Format::R8_UNORM ||
301 : #endif
302 0 : texture->GetFormat() == Format::A8_UNORM)
303 : {
304 0 : ENSURE(texture->GetFormat() == dataFormat);
305 0 : size_t bytesPerPixel = 4;
306 0 : GLenum pixelFormat = GL_RGBA;
307 0 : switch (dataFormat)
308 : {
309 0 : case Format::R8G8B8A8_UNORM:
310 0 : break;
311 0 : case Format::R8G8B8_UNORM:
312 0 : pixelFormat = GL_RGB;
313 0 : bytesPerPixel = 3;
314 0 : break;
315 : #if !CONFIG2_GLES
316 0 : case Format::R8_UNORM:
317 0 : pixelFormat = GL_RED;
318 0 : bytesPerPixel = 1;
319 0 : break;
320 : #endif
321 0 : case Format::A8_UNORM:
322 0 : pixelFormat = GL_ALPHA;
323 0 : bytesPerPixel = 1;
324 0 : break;
325 0 : case Format::L8_UNORM:
326 0 : pixelFormat = GL_LUMINANCE;
327 0 : bytesPerPixel = 1;
328 0 : break;
329 0 : default:
330 0 : debug_warn("Unexpected format.");
331 0 : break;
332 : }
333 0 : ENSURE(dataSize == width * height * bytesPerPixel);
334 :
335 0 : ScopedBind scopedBind(this, GL_TEXTURE_2D, texture->GetHandle());
336 0 : glTexSubImage2D(GL_TEXTURE_2D, level,
337 : xOffset, yOffset, width, height,
338 : pixelFormat, GL_UNSIGNED_BYTE, data);
339 0 : ogl_WarnIfError();
340 : }
341 0 : else if (
342 0 : texture->GetFormat() == Format::BC1_RGB_UNORM ||
343 0 : texture->GetFormat() == Format::BC1_RGBA_UNORM ||
344 0 : texture->GetFormat() == Format::BC2_UNORM ||
345 0 : texture->GetFormat() == Format::BC3_UNORM)
346 : {
347 0 : ENSURE(xOffset == 0 && yOffset == 0);
348 0 : ENSURE(texture->GetFormat() == dataFormat);
349 : // TODO: add data size check.
350 :
351 0 : GLenum internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
352 0 : switch (texture->GetFormat())
353 : {
354 0 : case Format::BC1_RGBA_UNORM:
355 0 : internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
356 0 : break;
357 0 : case Format::BC2_UNORM:
358 0 : internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
359 0 : break;
360 0 : case Format::BC3_UNORM:
361 0 : internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
362 0 : break;
363 0 : default:
364 0 : break;
365 : }
366 :
367 0 : ScopedBind scopedBind(this, GL_TEXTURE_2D, texture->GetHandle());
368 0 : glCompressedTexImage2DARB(GL_TEXTURE_2D, level, internalFormat, width, height, 0, dataSize, data);
369 0 : ogl_WarnIfError();
370 : }
371 : else
372 0 : debug_warn("Unsupported format");
373 : }
374 0 : else if (texture->GetType() == CTexture::Type::TEXTURE_CUBE)
375 : {
376 0 : if (texture->GetFormat() == Format::R8G8B8A8_UNORM)
377 : {
378 0 : ENSURE(texture->GetFormat() == dataFormat);
379 0 : ENSURE(level == 0 && layer < 6);
380 0 : ENSURE(xOffset == 0 && yOffset == 0 && texture->GetWidth() == width && texture->GetHeight() == height);
381 0 : const size_t bpp = 4;
382 0 : ENSURE(dataSize == width * height * bpp);
383 :
384 : // The order of layers should be the following:
385 : // front, back, top, bottom, right, left
386 : static const GLenum targets[6] =
387 : {
388 : GL_TEXTURE_CUBE_MAP_POSITIVE_X,
389 : GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
390 : GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
391 : GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
392 : GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
393 : GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
394 : };
395 :
396 0 : ScopedBind scopedBind(this, GL_TEXTURE_CUBE_MAP, texture->GetHandle());
397 0 : glTexImage2D(targets[layer], level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
398 0 : ogl_WarnIfError();
399 : }
400 : else
401 0 : debug_warn("Unsupported format");
402 : }
403 : else
404 0 : debug_warn("Unsupported type");
405 0 : }
406 :
407 0 : void CDeviceCommandContext::UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize)
408 : {
409 0 : ENSURE(!m_InsideFramebufferPass);
410 0 : UploadBufferRegion(buffer, data, dataSize, 0);
411 0 : }
412 :
413 0 : void CDeviceCommandContext::UploadBuffer(
414 : IBuffer* buffer, const UploadBufferFunction& uploadFunction)
415 : {
416 0 : ENSURE(!m_InsideFramebufferPass);
417 0 : UploadBufferRegion(buffer, 0, buffer->GetSize(), uploadFunction);
418 0 : }
419 :
420 0 : void CDeviceCommandContext::UploadBufferRegion(
421 : IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize)
422 : {
423 0 : ENSURE(!m_InsideFramebufferPass);
424 0 : ENSURE(data);
425 0 : ENSURE(dataOffset + dataSize <= buffer->GetSize());
426 0 : const GLenum target = BufferTypeToGLTarget(buffer->GetType());
427 0 : ScopedBufferBind scopedBufferBind(this, buffer->As<CBuffer>());
428 0 : if (buffer->IsDynamic())
429 : {
430 0 : UploadDynamicBufferRegionImpl(target, buffer->GetSize(), dataOffset, dataSize, [data, dataSize](u8* mappedData)
431 0 : {
432 0 : std::memcpy(mappedData, data, dataSize);
433 0 : });
434 : }
435 : else
436 : {
437 0 : glBufferSubDataARB(target, dataOffset, dataSize, data);
438 0 : ogl_WarnIfError();
439 : }
440 0 : }
441 :
442 0 : void CDeviceCommandContext::UploadBufferRegion(
443 : IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize,
444 : const UploadBufferFunction& uploadFunction)
445 : {
446 0 : ENSURE(!m_InsideFramebufferPass);
447 0 : ENSURE(dataOffset + dataSize <= buffer->GetSize());
448 0 : const GLenum target = BufferTypeToGLTarget(buffer->GetType());
449 0 : ScopedBufferBind scopedBufferBind(this, buffer->As<CBuffer>());
450 0 : ENSURE(buffer->IsDynamic());
451 0 : UploadDynamicBufferRegionImpl(target, buffer->GetSize(), dataOffset, dataSize, uploadFunction);
452 0 : }
453 :
454 0 : void CDeviceCommandContext::BeginScopedLabel(const char* name)
455 : {
456 0 : if (!m_Device->GetCapabilities().debugScopedLabels)
457 0 : return;
458 :
459 0 : ++m_ScopedLabelDepth;
460 0 : glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0x0AD, -1, name);
461 : }
462 :
463 0 : void CDeviceCommandContext::EndScopedLabel()
464 : {
465 0 : if (!m_Device->GetCapabilities().debugScopedLabels)
466 0 : return;
467 :
468 0 : ENSURE(m_ScopedLabelDepth > 0);
469 0 : --m_ScopedLabelDepth;
470 0 : glPopDebugGroup();
471 : }
472 :
473 0 : void CDeviceCommandContext::BindTexture(
474 : const uint32_t unit, const GLenum target, const GLuint handle)
475 : {
476 0 : ENSURE(unit < m_BoundTextures.size());
477 : #if CONFIG2_GLES
478 : ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
479 : #else
480 0 : ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_2D_MULTISAMPLE);
481 : #endif
482 0 : if (m_ActiveTextureUnit != unit)
483 : {
484 0 : glActiveTexture(GL_TEXTURE0 + unit);
485 0 : m_ActiveTextureUnit = unit;
486 : }
487 0 : if (m_BoundTextures[unit].target == target && m_BoundTextures[unit].handle == handle)
488 0 : return;
489 0 : if (m_BoundTextures[unit].target != target && m_BoundTextures[unit].target && m_BoundTextures[unit].handle)
490 0 : glBindTexture(m_BoundTextures[unit].target, 0);
491 0 : if (m_BoundTextures[unit].handle != handle)
492 0 : glBindTexture(target, handle);
493 0 : ogl_WarnIfError();
494 0 : m_BoundTextures[unit] = {target, handle};
495 : }
496 :
497 0 : void CDeviceCommandContext::BindBuffer(const IBuffer::Type type, CBuffer* buffer)
498 : {
499 0 : ENSURE(!buffer || buffer->GetType() == type);
500 0 : if (type == IBuffer::Type::VERTEX)
501 : {
502 0 : if (m_VertexBuffer == buffer)
503 0 : return;
504 0 : m_VertexBuffer = buffer;
505 : }
506 0 : else if (type == IBuffer::Type::INDEX)
507 : {
508 0 : if (!buffer)
509 0 : m_IndexBuffer = nullptr;
510 0 : m_IndexBufferData = nullptr;
511 : }
512 0 : const GLenum target = BufferTypeToGLTarget(type);
513 0 : const GLuint handle = buffer ? buffer->GetHandle() : 0;
514 0 : glBindBufferARB(target, handle);
515 0 : ogl_WarnIfError();
516 0 : const size_t cacheIndex = static_cast<size_t>(type);
517 0 : ENSURE(cacheIndex < m_BoundBuffers.size());
518 0 : m_BoundBuffers[cacheIndex].second = handle;
519 : }
520 :
521 0 : void CDeviceCommandContext::OnTextureDestroy(CTexture* texture)
522 : {
523 0 : ENSURE(texture);
524 0 : for (size_t index = 0; index < m_BoundTextures.size(); ++index)
525 0 : if (m_BoundTextures[index].handle == texture->GetHandle())
526 0 : BindTexture(index, GL_TEXTURE_2D, 0);
527 0 : }
528 :
529 0 : void CDeviceCommandContext::Flush()
530 : {
531 0 : ENSURE(m_ScopedLabelDepth == 0);
532 :
533 0 : GPU_SCOPED_LABEL(this, "CDeviceCommandContext::Flush");
534 :
535 0 : ResetStates();
536 :
537 0 : m_IndexBuffer = nullptr;
538 0 : m_IndexBufferData = nullptr;
539 :
540 0 : for (size_t unit = 0; unit < m_BoundTextures.size(); ++unit)
541 : {
542 0 : if (m_BoundTextures[unit].handle)
543 0 : BindTexture(unit, GL_TEXTURE_2D, 0);
544 : }
545 0 : BindBuffer(CBuffer::Type::INDEX, nullptr);
546 0 : BindBuffer(CBuffer::Type::VERTEX, nullptr);
547 0 : }
548 :
549 0 : void CDeviceCommandContext::ResetStates()
550 : {
551 0 : SetGraphicsPipelineStateImpl(MakeDefaultGraphicsPipelineStateDesc(), true);
552 0 : SetScissors(0, nullptr);
553 0 : m_Framebuffer = m_Device->GetCurrentBackbuffer(
554 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
555 : Renderer::Backend::AttachmentStoreOp::DONT_CARE,
556 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
557 0 : Renderer::Backend::AttachmentStoreOp::DONT_CARE)->As<CFramebuffer>();
558 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_Framebuffer->GetHandle());
559 0 : ogl_WarnIfError();
560 0 : }
561 :
562 0 : void CDeviceCommandContext::SetGraphicsPipelineStateImpl(
563 : const SGraphicsPipelineStateDesc& pipelineStateDesc, const bool force)
564 : {
565 0 : ENSURE(!m_InsidePass);
566 :
567 0 : if (m_GraphicsPipelineStateDesc.shaderProgram != pipelineStateDesc.shaderProgram)
568 : {
569 0 : CShaderProgram* currentShaderProgram = nullptr;
570 0 : if (m_GraphicsPipelineStateDesc.shaderProgram)
571 : {
572 0 : currentShaderProgram =
573 : static_cast<CShaderProgram*>(m_GraphicsPipelineStateDesc.shaderProgram);
574 : }
575 0 : CShaderProgram* nextShaderProgram = nullptr;
576 0 : if (pipelineStateDesc.shaderProgram)
577 : {
578 0 : nextShaderProgram =
579 : static_cast<CShaderProgram*>(pipelineStateDesc.shaderProgram);
580 0 : for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index)
581 : {
582 0 : const VertexAttributeStream stream = static_cast<VertexAttributeStream>(index);
583 0 : m_VertexAttributeFormat[index].active = nextShaderProgram->IsStreamActive(stream);
584 0 : m_VertexAttributeFormat[index].initialized = false;
585 0 : m_VertexAttributeFormat[index].bindingSlot = std::numeric_limits<uint32_t>::max();
586 : }
587 : }
588 0 : if (nextShaderProgram)
589 0 : nextShaderProgram->Bind(currentShaderProgram);
590 0 : else if (currentShaderProgram)
591 0 : currentShaderProgram->Unbind();
592 :
593 0 : m_ShaderProgram = nextShaderProgram;
594 : }
595 :
596 0 : const SDepthStencilStateDesc& currentDepthStencilStateDesc = m_GraphicsPipelineStateDesc.depthStencilState;
597 0 : const SDepthStencilStateDesc& nextDepthStencilStateDesc = pipelineStateDesc.depthStencilState;
598 0 : if (force || currentDepthStencilStateDesc.depthTestEnabled != nextDepthStencilStateDesc.depthTestEnabled)
599 : {
600 0 : if (nextDepthStencilStateDesc.depthTestEnabled)
601 0 : glEnable(GL_DEPTH_TEST);
602 : else
603 0 : glDisable(GL_DEPTH_TEST);
604 : }
605 0 : if (force || currentDepthStencilStateDesc.depthCompareOp != nextDepthStencilStateDesc.depthCompareOp)
606 : {
607 0 : glDepthFunc(Mapping::FromCompareOp(nextDepthStencilStateDesc.depthCompareOp));
608 : }
609 0 : if (force || currentDepthStencilStateDesc.depthWriteEnabled != nextDepthStencilStateDesc.depthWriteEnabled)
610 : {
611 0 : ApplyDepthMask(nextDepthStencilStateDesc.depthWriteEnabled);
612 : }
613 :
614 0 : if (force || currentDepthStencilStateDesc.stencilTestEnabled != nextDepthStencilStateDesc.stencilTestEnabled)
615 : {
616 0 : if (nextDepthStencilStateDesc.stencilTestEnabled)
617 0 : glEnable(GL_STENCIL_TEST);
618 : else
619 0 : glDisable(GL_STENCIL_TEST);
620 : }
621 0 : if (force ||
622 0 : currentDepthStencilStateDesc.stencilFrontFace != nextDepthStencilStateDesc.stencilFrontFace ||
623 0 : currentDepthStencilStateDesc.stencilBackFace != nextDepthStencilStateDesc.stencilBackFace)
624 : {
625 0 : if (nextDepthStencilStateDesc.stencilFrontFace == nextDepthStencilStateDesc.stencilBackFace)
626 : {
627 0 : glStencilOp(
628 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.failOp),
629 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.depthFailOp),
630 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.passOp));
631 : }
632 : else
633 : {
634 0 : if (force || currentDepthStencilStateDesc.stencilFrontFace != nextDepthStencilStateDesc.stencilFrontFace)
635 : {
636 0 : glStencilOpSeparate(
637 : GL_FRONT,
638 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.failOp),
639 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.depthFailOp),
640 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilFrontFace.passOp));
641 : }
642 0 : if (force || currentDepthStencilStateDesc.stencilBackFace != nextDepthStencilStateDesc.stencilBackFace)
643 : {
644 0 : glStencilOpSeparate(
645 : GL_BACK,
646 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilBackFace.failOp),
647 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilBackFace.depthFailOp),
648 0 : Mapping::FromStencilOp(nextDepthStencilStateDesc.stencilBackFace.passOp));
649 : }
650 : }
651 : }
652 0 : if (force || currentDepthStencilStateDesc.stencilWriteMask != nextDepthStencilStateDesc.stencilWriteMask)
653 : {
654 0 : ApplyStencilMask(nextDepthStencilStateDesc.stencilWriteMask);
655 : }
656 0 : if (force ||
657 0 : currentDepthStencilStateDesc.stencilReference != nextDepthStencilStateDesc.stencilReference ||
658 0 : currentDepthStencilStateDesc.stencilReadMask != nextDepthStencilStateDesc.stencilReadMask ||
659 0 : currentDepthStencilStateDesc.stencilFrontFace.compareOp != nextDepthStencilStateDesc.stencilFrontFace.compareOp ||
660 0 : currentDepthStencilStateDesc.stencilBackFace.compareOp != nextDepthStencilStateDesc.stencilBackFace.compareOp)
661 : {
662 0 : if (nextDepthStencilStateDesc.stencilFrontFace.compareOp == nextDepthStencilStateDesc.stencilBackFace.compareOp)
663 : {
664 0 : glStencilFunc(
665 0 : Mapping::FromCompareOp(nextDepthStencilStateDesc.stencilFrontFace.compareOp),
666 0 : nextDepthStencilStateDesc.stencilReference,
667 0 : nextDepthStencilStateDesc.stencilReadMask);
668 : }
669 : else
670 : {
671 0 : glStencilFuncSeparate(GL_FRONT,
672 0 : Mapping::FromCompareOp(nextDepthStencilStateDesc.stencilFrontFace.compareOp),
673 0 : nextDepthStencilStateDesc.stencilReference,
674 0 : nextDepthStencilStateDesc.stencilReadMask);
675 0 : glStencilFuncSeparate(GL_BACK,
676 0 : Mapping::FromCompareOp(nextDepthStencilStateDesc.stencilBackFace.compareOp),
677 0 : nextDepthStencilStateDesc.stencilReference,
678 0 : nextDepthStencilStateDesc.stencilReadMask);
679 : }
680 : }
681 :
682 0 : const SBlendStateDesc& currentBlendStateDesc = m_GraphicsPipelineStateDesc.blendState;
683 0 : const SBlendStateDesc& nextBlendStateDesc = pipelineStateDesc.blendState;
684 0 : if (force || currentBlendStateDesc.enabled != nextBlendStateDesc.enabled)
685 : {
686 0 : if (nextBlendStateDesc.enabled)
687 0 : glEnable(GL_BLEND);
688 : else
689 0 : glDisable(GL_BLEND);
690 : }
691 0 : if (force ||
692 0 : currentBlendStateDesc.srcColorBlendFactor != nextBlendStateDesc.srcColorBlendFactor ||
693 0 : currentBlendStateDesc.srcAlphaBlendFactor != nextBlendStateDesc.srcAlphaBlendFactor ||
694 0 : currentBlendStateDesc.dstColorBlendFactor != nextBlendStateDesc.dstColorBlendFactor ||
695 0 : currentBlendStateDesc.dstAlphaBlendFactor != nextBlendStateDesc.dstAlphaBlendFactor)
696 : {
697 0 : if (nextBlendStateDesc.srcColorBlendFactor == nextBlendStateDesc.srcAlphaBlendFactor &&
698 0 : nextBlendStateDesc.dstColorBlendFactor == nextBlendStateDesc.dstAlphaBlendFactor)
699 : {
700 0 : glBlendFunc(
701 0 : Mapping::FromBlendFactor(nextBlendStateDesc.srcColorBlendFactor),
702 0 : Mapping::FromBlendFactor(nextBlendStateDesc.dstColorBlendFactor));
703 : }
704 : else
705 : {
706 0 : glBlendFuncSeparate(
707 0 : Mapping::FromBlendFactor(nextBlendStateDesc.srcColorBlendFactor),
708 0 : Mapping::FromBlendFactor(nextBlendStateDesc.dstColorBlendFactor),
709 0 : Mapping::FromBlendFactor(nextBlendStateDesc.srcAlphaBlendFactor),
710 0 : Mapping::FromBlendFactor(nextBlendStateDesc.dstAlphaBlendFactor));
711 : }
712 : }
713 :
714 0 : if (force ||
715 0 : currentBlendStateDesc.colorBlendOp != nextBlendStateDesc.colorBlendOp ||
716 0 : currentBlendStateDesc.alphaBlendOp != nextBlendStateDesc.alphaBlendOp)
717 : {
718 0 : if (nextBlendStateDesc.colorBlendOp == nextBlendStateDesc.alphaBlendOp)
719 : {
720 0 : glBlendEquation(Mapping::FromBlendOp(nextBlendStateDesc.colorBlendOp));
721 : }
722 : else
723 : {
724 0 : glBlendEquationSeparate(
725 0 : Mapping::FromBlendOp(nextBlendStateDesc.colorBlendOp),
726 0 : Mapping::FromBlendOp(nextBlendStateDesc.alphaBlendOp));
727 : }
728 : }
729 :
730 0 : if (force ||
731 0 : currentBlendStateDesc.constant != nextBlendStateDesc.constant)
732 : {
733 0 : glBlendColor(
734 0 : nextBlendStateDesc.constant.r,
735 0 : nextBlendStateDesc.constant.g,
736 0 : nextBlendStateDesc.constant.b,
737 0 : nextBlendStateDesc.constant.a);
738 : }
739 :
740 0 : if (force ||
741 0 : currentBlendStateDesc.colorWriteMask != nextBlendStateDesc.colorWriteMask)
742 : {
743 0 : ApplyColorMask(nextBlendStateDesc.colorWriteMask);
744 : }
745 :
746 0 : const SRasterizationStateDesc& currentRasterizationStateDesc =
747 : m_GraphicsPipelineStateDesc.rasterizationState;
748 0 : const SRasterizationStateDesc& nextRasterizationStateDesc =
749 : pipelineStateDesc.rasterizationState;
750 0 : if (force ||
751 0 : currentRasterizationStateDesc.polygonMode != nextRasterizationStateDesc.polygonMode)
752 : {
753 : #if !CONFIG2_GLES
754 0 : glPolygonMode(
755 : GL_FRONT_AND_BACK,
756 0 : nextRasterizationStateDesc.polygonMode == PolygonMode::LINE ? GL_LINE : GL_FILL);
757 : #endif
758 : }
759 :
760 0 : if (force ||
761 0 : currentRasterizationStateDesc.cullMode != nextRasterizationStateDesc.cullMode)
762 : {
763 0 : if (nextRasterizationStateDesc.cullMode == CullMode::NONE)
764 : {
765 0 : glDisable(GL_CULL_FACE);
766 : }
767 : else
768 : {
769 0 : if (force || currentRasterizationStateDesc.cullMode == CullMode::NONE)
770 0 : glEnable(GL_CULL_FACE);
771 0 : glCullFace(nextRasterizationStateDesc.cullMode == CullMode::FRONT ? GL_FRONT : GL_BACK);
772 : }
773 : }
774 :
775 0 : if (force ||
776 0 : currentRasterizationStateDesc.frontFace != nextRasterizationStateDesc.frontFace)
777 : {
778 0 : if (nextRasterizationStateDesc.frontFace == FrontFace::CLOCKWISE)
779 0 : glFrontFace(GL_CW);
780 : else
781 0 : glFrontFace(GL_CCW);
782 : }
783 :
784 : #if !CONFIG2_GLES
785 0 : if (force ||
786 0 : currentRasterizationStateDesc.depthBiasEnabled != nextRasterizationStateDesc.depthBiasEnabled)
787 : {
788 0 : if (nextRasterizationStateDesc.depthBiasEnabled)
789 0 : glEnable(GL_POLYGON_OFFSET_FILL);
790 : else
791 0 : glDisable(GL_POLYGON_OFFSET_FILL);
792 : }
793 0 : if (force ||
794 0 : currentRasterizationStateDesc.depthBiasConstantFactor != nextRasterizationStateDesc.depthBiasConstantFactor ||
795 0 : currentRasterizationStateDesc.depthBiasSlopeFactor != nextRasterizationStateDesc.depthBiasSlopeFactor)
796 : {
797 0 : glPolygonOffset(
798 0 : nextRasterizationStateDesc.depthBiasSlopeFactor,
799 0 : nextRasterizationStateDesc.depthBiasConstantFactor);
800 : }
801 : #endif
802 :
803 0 : ogl_WarnIfError();
804 :
805 0 : m_GraphicsPipelineStateDesc = pipelineStateDesc;
806 0 : }
807 :
808 0 : void CDeviceCommandContext::BlitFramebuffer(
809 : IFramebuffer* dstFramebuffer, IFramebuffer* srcFramebuffer)
810 : {
811 0 : ENSURE(!m_InsideFramebufferPass);
812 0 : CFramebuffer* destinationFramebuffer = dstFramebuffer->As<CFramebuffer>();
813 0 : CFramebuffer* sourceFramebuffer = srcFramebuffer->As<CFramebuffer>();
814 : #if CONFIG2_GLES
815 : UNUSED2(destinationFramebuffer);
816 : UNUSED2(sourceFramebuffer);
817 : debug_warn("CDeviceCommandContext::BlitFramebuffer is not implemented for GLES");
818 : #else
819 : // Source framebuffer should not be backbuffer.
820 0 : ENSURE(sourceFramebuffer->GetHandle() != 0);
821 0 : ENSURE(destinationFramebuffer != sourceFramebuffer);
822 0 : glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, sourceFramebuffer->GetHandle());
823 0 : glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, destinationFramebuffer->GetHandle());
824 : // TODO: add more check for internal formats. And currently we don't support
825 : // scaling inside blit.
826 0 : glBlitFramebufferEXT(
827 0 : 0, 0, sourceFramebuffer->GetWidth(), sourceFramebuffer->GetHeight(),
828 0 : 0, 0, sourceFramebuffer->GetWidth(), sourceFramebuffer->GetHeight(),
829 0 : (sourceFramebuffer->GetAttachmentMask() & destinationFramebuffer->GetAttachmentMask()),
830 : GL_NEAREST);
831 0 : ogl_WarnIfError();
832 : #endif
833 0 : }
834 :
835 0 : void CDeviceCommandContext::ClearFramebuffer(const bool color, const bool depth, const bool stencil)
836 : {
837 0 : ENSURE(m_InsideFramebufferPass);
838 0 : const bool needsColor = color && (m_Framebuffer->GetAttachmentMask() & GL_COLOR_BUFFER_BIT) != 0;
839 0 : const bool needsDepth = depth && (m_Framebuffer->GetAttachmentMask() & GL_DEPTH_BUFFER_BIT) != 0;
840 0 : const bool needsStencil = stencil && (m_Framebuffer->GetAttachmentMask() & GL_STENCIL_BUFFER_BIT) != 0;
841 0 : GLbitfield mask = 0;
842 0 : if (needsColor)
843 : {
844 0 : ApplyColorMask(ColorWriteMask::RED | ColorWriteMask::GREEN | ColorWriteMask::BLUE | ColorWriteMask::ALPHA);
845 0 : glClearColor(
846 0 : m_Framebuffer->GetClearColor().r,
847 0 : m_Framebuffer->GetClearColor().g,
848 0 : m_Framebuffer->GetClearColor().b,
849 0 : m_Framebuffer->GetClearColor().a);
850 0 : mask |= GL_COLOR_BUFFER_BIT;
851 : }
852 0 : if (needsDepth)
853 : {
854 0 : ApplyDepthMask(true);
855 0 : mask |= GL_DEPTH_BUFFER_BIT;
856 : }
857 0 : if (needsStencil)
858 : {
859 0 : ApplyStencilMask(std::numeric_limits<uint32_t>::max());
860 0 : mask |= GL_STENCIL_BUFFER_BIT;
861 : }
862 0 : glClear(mask);
863 0 : ogl_WarnIfError();
864 0 : if (needsColor)
865 0 : ApplyColorMask(m_GraphicsPipelineStateDesc.blendState.colorWriteMask);
866 0 : if (needsDepth)
867 0 : ApplyDepthMask(m_GraphicsPipelineStateDesc.depthStencilState.depthWriteEnabled);
868 0 : if (needsStencil)
869 0 : ApplyStencilMask(m_GraphicsPipelineStateDesc.depthStencilState.stencilWriteMask);
870 0 : }
871 :
872 0 : void CDeviceCommandContext::BeginFramebufferPass(IFramebuffer* framebuffer)
873 : {
874 0 : SetGraphicsPipelineStateImpl(
875 0 : MakeDefaultGraphicsPipelineStateDesc(), false);
876 :
877 0 : ENSURE(!m_InsideFramebufferPass);
878 0 : m_InsideFramebufferPass = true;
879 0 : ENSURE(framebuffer);
880 0 : m_Framebuffer = framebuffer->As<CFramebuffer>();
881 0 : ENSURE(m_Framebuffer->GetHandle() == 0 || (m_Framebuffer->GetWidth() > 0 && m_Framebuffer->GetHeight() > 0));
882 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_Framebuffer->GetHandle());
883 0 : ogl_WarnIfError();
884 0 : if (m_Device->UseFramebufferInvalidating())
885 : {
886 0 : InvalidateFramebuffer(
887 : m_Framebuffer,
888 0 : m_Framebuffer->GetColorAttachmentLoadOp() != AttachmentLoadOp::LOAD,
889 0 : m_Framebuffer->GetDepthStencilAttachmentLoadOp() != AttachmentLoadOp::LOAD);
890 : }
891 : const bool needsClearColor =
892 0 : m_Framebuffer->GetColorAttachmentLoadOp() == AttachmentLoadOp::CLEAR;
893 : const bool needsClearDepthStencil =
894 0 : m_Framebuffer->GetDepthStencilAttachmentLoadOp() == AttachmentLoadOp::CLEAR;
895 0 : if (needsClearColor || needsClearDepthStencil)
896 : {
897 0 : ClearFramebuffer(
898 : needsClearColor, needsClearDepthStencil, needsClearDepthStencil);
899 : }
900 0 : }
901 :
902 0 : void CDeviceCommandContext::EndFramebufferPass()
903 : {
904 0 : if (m_Device->UseFramebufferInvalidating())
905 : {
906 0 : InvalidateFramebuffer(
907 : m_Framebuffer,
908 0 : m_Framebuffer->GetColorAttachmentStoreOp() != AttachmentStoreOp::STORE,
909 0 : m_Framebuffer->GetDepthStencilAttachmentStoreOp() != AttachmentStoreOp::STORE);
910 : }
911 0 : ENSURE(m_InsideFramebufferPass);
912 0 : m_InsideFramebufferPass = false;
913 0 : CFramebuffer* framebuffer = m_Device->GetCurrentBackbuffer(
914 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
915 : Renderer::Backend::AttachmentStoreOp::DONT_CARE,
916 : Renderer::Backend::AttachmentLoadOp::DONT_CARE,
917 0 : Renderer::Backend::AttachmentStoreOp::DONT_CARE)->As<CFramebuffer>();
918 0 : if (framebuffer->GetHandle() != m_Framebuffer->GetHandle())
919 : {
920 0 : glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->GetHandle());
921 0 : ogl_WarnIfError();
922 : }
923 0 : m_Framebuffer = framebuffer;
924 0 : }
925 :
926 0 : void CDeviceCommandContext::ReadbackFramebufferSync(
927 : const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height,
928 : void* data)
929 : {
930 0 : ENSURE(m_Framebuffer);
931 0 : glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
932 0 : ogl_WarnIfError();
933 0 : }
934 :
935 0 : void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const Rect* scissors)
936 : {
937 0 : ENSURE(scissorCount <= 1);
938 0 : if (scissorCount == 0)
939 : {
940 0 : if (m_ScissorCount != scissorCount)
941 0 : glDisable(GL_SCISSOR_TEST);
942 : }
943 : else
944 : {
945 0 : if (m_ScissorCount != scissorCount)
946 0 : glEnable(GL_SCISSOR_TEST);
947 0 : ENSURE(scissors);
948 0 : if (m_ScissorCount != scissorCount || m_Scissors[0] != scissors[0])
949 : {
950 0 : m_Scissors[0] = scissors[0];
951 0 : glScissor(m_Scissors[0].x, m_Scissors[0].y, m_Scissors[0].width, m_Scissors[0].height);
952 : }
953 : }
954 0 : ogl_WarnIfError();
955 0 : m_ScissorCount = scissorCount;
956 0 : }
957 :
958 0 : void CDeviceCommandContext::SetViewports(const uint32_t viewportCount, const Rect* viewports)
959 : {
960 0 : ENSURE(m_InsideFramebufferPass);
961 0 : ENSURE(viewportCount == 1);
962 0 : glViewport(viewports[0].x, viewports[0].y, viewports[0].width, viewports[0].height);
963 0 : ogl_WarnIfError();
964 0 : }
965 :
966 0 : void CDeviceCommandContext::SetVertexInputLayout(
967 : IVertexInputLayout* vertexInputLayout)
968 : {
969 0 : ENSURE(vertexInputLayout);
970 0 : for (const SVertexAttributeFormat& attribute : vertexInputLayout->As<CVertexInputLayout>()->GetAttributes())
971 : {
972 0 : const uint32_t index = static_cast<uint32_t>(attribute.stream);
973 0 : ENSURE(index < m_VertexAttributeFormat.size());
974 0 : ENSURE(attribute.bindingSlot < m_VertexAttributeFormat.size());
975 0 : if (!m_VertexAttributeFormat[index].active)
976 0 : continue;
977 :
978 0 : m_VertexAttributeFormat[index].format = attribute.format;
979 0 : m_VertexAttributeFormat[index].offset = attribute.offset;
980 0 : m_VertexAttributeFormat[index].stride = attribute.stride;
981 0 : m_VertexAttributeFormat[index].rate = attribute.rate;
982 0 : m_VertexAttributeFormat[index].bindingSlot = attribute.bindingSlot;
983 :
984 0 : m_VertexAttributeFormat[index].initialized = true;
985 : }
986 0 : }
987 :
988 0 : void CDeviceCommandContext::SetVertexBuffer(
989 : const uint32_t bindingSlot, IBuffer* buffer, const uint32_t offset)
990 : {
991 0 : ENSURE(buffer);
992 0 : ENSURE(buffer->GetType() == IBuffer::Type::VERTEX);
993 0 : ENSURE(m_ShaderProgram);
994 0 : BindBuffer(buffer->GetType(), buffer->As<CBuffer>());
995 0 : for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index)
996 : {
997 0 : if (!m_VertexAttributeFormat[index].active || m_VertexAttributeFormat[index].bindingSlot != bindingSlot)
998 0 : continue;
999 0 : ENSURE(m_VertexAttributeFormat[index].initialized);
1000 0 : const VertexAttributeStream stream = static_cast<VertexAttributeStream>(index);
1001 0 : m_ShaderProgram->VertexAttribPointer(stream,
1002 0 : m_VertexAttributeFormat[index].format,
1003 0 : m_VertexAttributeFormat[index].offset + offset,
1004 0 : m_VertexAttributeFormat[index].stride,
1005 0 : m_VertexAttributeFormat[index].rate,
1006 0 : nullptr);
1007 : }
1008 0 : }
1009 :
1010 0 : void CDeviceCommandContext::SetVertexBufferData(
1011 : const uint32_t bindingSlot, const void* data, const uint32_t dataSize)
1012 : {
1013 0 : ENSURE(data);
1014 0 : ENSURE(m_ShaderProgram);
1015 0 : ENSURE(dataSize > 0);
1016 0 : BindBuffer(CBuffer::Type::VERTEX, nullptr);
1017 0 : for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index)
1018 : {
1019 0 : if (!m_VertexAttributeFormat[index].active || m_VertexAttributeFormat[index].bindingSlot != bindingSlot)
1020 0 : continue;
1021 0 : ENSURE(m_VertexAttributeFormat[index].initialized);
1022 0 : const VertexAttributeStream stream = static_cast<VertexAttributeStream>(index);
1023 : // We don't know how many vertices will be used in a draw command, so we
1024 : // assume at least one vertex.
1025 0 : ENSURE(dataSize >= m_VertexAttributeFormat[index].offset + m_VertexAttributeFormat[index].stride);
1026 0 : m_ShaderProgram->VertexAttribPointer(stream,
1027 0 : m_VertexAttributeFormat[index].format,
1028 0 : m_VertexAttributeFormat[index].offset,
1029 0 : m_VertexAttributeFormat[index].stride,
1030 0 : m_VertexAttributeFormat[index].rate,
1031 0 : data);
1032 : }
1033 0 : }
1034 :
1035 0 : void CDeviceCommandContext::SetIndexBuffer(IBuffer* buffer)
1036 : {
1037 0 : ENSURE(buffer->GetType() == CBuffer::Type::INDEX);
1038 0 : m_IndexBuffer = buffer->As<CBuffer>();
1039 0 : m_IndexBufferData = nullptr;
1040 0 : BindBuffer(CBuffer::Type::INDEX, m_IndexBuffer);
1041 0 : }
1042 :
1043 0 : void CDeviceCommandContext::SetIndexBufferData(const void* data, const uint32_t dataSize)
1044 : {
1045 0 : ENSURE(dataSize > 0);
1046 0 : if (m_IndexBuffer)
1047 : {
1048 0 : BindBuffer(CBuffer::Type::INDEX, nullptr);
1049 0 : m_IndexBuffer = nullptr;
1050 : }
1051 0 : m_IndexBufferData = data;
1052 0 : }
1053 :
1054 0 : void CDeviceCommandContext::BeginPass()
1055 : {
1056 0 : ENSURE(!m_InsidePass);
1057 0 : m_InsidePass = true;
1058 0 : }
1059 :
1060 0 : void CDeviceCommandContext::EndPass()
1061 : {
1062 0 : ENSURE(m_InsidePass);
1063 0 : m_InsidePass = false;
1064 0 : }
1065 :
1066 0 : void CDeviceCommandContext::Draw(
1067 : const uint32_t firstVertex, const uint32_t vertexCount)
1068 : {
1069 0 : ENSURE(m_ShaderProgram);
1070 0 : ENSURE(m_InsidePass);
1071 : // Some drivers apparently don't like count = 0 in glDrawArrays here, so skip
1072 : // all drawing in that case.
1073 0 : if (vertexCount == 0)
1074 0 : return;
1075 0 : m_ShaderProgram->AssertPointersBound();
1076 0 : glDrawArrays(GL_TRIANGLES, firstVertex, vertexCount);
1077 0 : ogl_WarnIfError();
1078 : }
1079 :
1080 0 : void CDeviceCommandContext::DrawIndexed(
1081 : const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset)
1082 : {
1083 0 : ENSURE(m_ShaderProgram);
1084 0 : ENSURE(m_InsidePass);
1085 0 : if (indexCount == 0)
1086 0 : return;
1087 0 : ENSURE(m_IndexBuffer || m_IndexBufferData);
1088 0 : ENSURE(vertexOffset == 0);
1089 0 : if (m_IndexBuffer)
1090 : {
1091 0 : ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize());
1092 : }
1093 0 : m_ShaderProgram->AssertPointersBound();
1094 : // Don't use glMultiDrawElements here since it doesn't have a significant
1095 : // performance impact and it suffers from various driver bugs (e.g. it breaks
1096 : // in Mesa 7.10 swrast with index VBOs).
1097 0 : glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT,
1098 0 : static_cast<const void*>((static_cast<const uint8_t*>(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)));
1099 0 : ogl_WarnIfError();
1100 : }
1101 :
1102 0 : void CDeviceCommandContext::DrawInstanced(
1103 : const uint32_t firstVertex, const uint32_t vertexCount,
1104 : const uint32_t firstInstance, const uint32_t instanceCount)
1105 : {
1106 0 : ENSURE(m_Device->GetCapabilities().instancing);
1107 0 : ENSURE(m_ShaderProgram);
1108 0 : ENSURE(m_InsidePass);
1109 0 : if (vertexCount == 0 || instanceCount == 0)
1110 0 : return;
1111 0 : ENSURE(firstInstance == 0);
1112 0 : m_ShaderProgram->AssertPointersBound();
1113 : #if CONFIG2_GLES
1114 : ENSURE(!m_Device->GetCapabilities().instancing);
1115 : UNUSED2(firstVertex);
1116 : UNUSED2(vertexCount);
1117 : UNUSED2(instanceCount);
1118 : #else
1119 0 : glDrawArraysInstancedARB(GL_TRIANGLES, firstVertex, vertexCount, instanceCount);
1120 : #endif
1121 0 : ogl_WarnIfError();
1122 : }
1123 :
1124 0 : void CDeviceCommandContext::DrawIndexedInstanced(
1125 : const uint32_t firstIndex, const uint32_t indexCount,
1126 : const uint32_t firstInstance, const uint32_t instanceCount,
1127 : const int32_t vertexOffset)
1128 : {
1129 0 : ENSURE(m_Device->GetCapabilities().instancing);
1130 0 : ENSURE(m_ShaderProgram);
1131 0 : ENSURE(m_InsidePass);
1132 0 : ENSURE(m_IndexBuffer || m_IndexBufferData);
1133 0 : if (indexCount == 0)
1134 0 : return;
1135 0 : ENSURE(firstInstance == 0 && vertexOffset == 0);
1136 0 : if (m_IndexBuffer)
1137 : {
1138 0 : ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize());
1139 : }
1140 0 : m_ShaderProgram->AssertPointersBound();
1141 : // Don't use glMultiDrawElements here since it doesn't have a significant
1142 : // performance impact and it suffers from various driver bugs (e.g. it breaks
1143 : // in Mesa 7.10 swrast with index VBOs).
1144 : #if CONFIG2_GLES
1145 : ENSURE(!m_Device->GetCapabilities().instancing);
1146 : UNUSED2(indexCount);
1147 : UNUSED2(firstIndex);
1148 : UNUSED2(instanceCount);
1149 : #else
1150 0 : glDrawElementsInstancedARB(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT,
1151 0 : static_cast<const void*>((static_cast<const uint8_t*>(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)),
1152 : instanceCount);
1153 : #endif
1154 0 : ogl_WarnIfError();
1155 : }
1156 :
1157 0 : void CDeviceCommandContext::DrawIndexedInRange(
1158 : const uint32_t firstIndex, const uint32_t indexCount,
1159 : const uint32_t start, const uint32_t end)
1160 : {
1161 0 : ENSURE(m_ShaderProgram);
1162 0 : ENSURE(m_InsidePass);
1163 0 : if (indexCount == 0)
1164 0 : return;
1165 0 : ENSURE(m_IndexBuffer || m_IndexBufferData);
1166 0 : const void* indices =
1167 0 : static_cast<const void*>((static_cast<const uint8_t*>(m_IndexBufferData) + sizeof(uint16_t) * firstIndex));
1168 0 : m_ShaderProgram->AssertPointersBound();
1169 : // Draw with DrawRangeElements where available, since it might be more
1170 : // efficient for slow hardware.
1171 : #if CONFIG2_GLES
1172 : UNUSED2(start);
1173 : UNUSED2(end);
1174 : glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices);
1175 : #else
1176 0 : glDrawRangeElementsEXT(GL_TRIANGLES, start, end, indexCount, GL_UNSIGNED_SHORT, indices);
1177 : #endif
1178 0 : ogl_WarnIfError();
1179 : }
1180 :
1181 0 : void CDeviceCommandContext::SetTexture(const int32_t bindingSlot, ITexture* texture)
1182 : {
1183 0 : ENSURE(m_ShaderProgram);
1184 0 : ENSURE(texture);
1185 0 : ENSURE(texture->GetUsage() & Renderer::Backend::ITexture::Usage::SAMPLED);
1186 :
1187 : const CShaderProgram::TextureUnit textureUnit =
1188 0 : m_ShaderProgram->GetTextureUnit(bindingSlot);
1189 0 : if (!textureUnit.type)
1190 0 : return;
1191 :
1192 0 : if (textureUnit.type != GL_SAMPLER_2D &&
1193 : #if !CONFIG2_GLES
1194 0 : textureUnit.type != GL_SAMPLER_2D_SHADOW &&
1195 : #endif
1196 0 : textureUnit.type != GL_SAMPLER_CUBE)
1197 : {
1198 0 : LOGERROR("CDeviceCommandContext::SetTexture: expected sampler at binding slot");
1199 0 : return;
1200 : }
1201 :
1202 : #if !CONFIG2_GLES
1203 0 : if (textureUnit.type == GL_SAMPLER_2D_SHADOW)
1204 : {
1205 0 : if (!IsDepthFormat(texture->GetFormat()))
1206 : {
1207 0 : LOGERROR("CDeviceCommandContext::SetTexture: Invalid texture type (expected depth texture)");
1208 0 : return;
1209 : }
1210 : }
1211 : #endif
1212 :
1213 0 : ENSURE(textureUnit.unit >= 0);
1214 0 : const uint32_t unit = textureUnit.unit;
1215 0 : if (unit >= m_BoundTextures.size())
1216 : {
1217 0 : LOGERROR("CDeviceCommandContext::SetTexture: Invalid texture unit (too big)");
1218 0 : return;
1219 : }
1220 0 : BindTexture(unit, textureUnit.target, texture->As<CTexture>()->GetHandle());
1221 : }
1222 :
1223 0 : void CDeviceCommandContext::SetUniform(
1224 : const int32_t bindingSlot,
1225 : const float value)
1226 : {
1227 0 : ENSURE(m_ShaderProgram);
1228 0 : m_ShaderProgram->SetUniform(bindingSlot, value);
1229 0 : }
1230 :
1231 0 : void CDeviceCommandContext::SetUniform(
1232 : const int32_t bindingSlot,
1233 : const float valueX, const float valueY)
1234 : {
1235 0 : ENSURE(m_ShaderProgram);
1236 0 : m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY);
1237 0 : }
1238 :
1239 0 : void CDeviceCommandContext::SetUniform(
1240 : const int32_t bindingSlot,
1241 : const float valueX, const float valueY,
1242 : const float valueZ)
1243 : {
1244 0 : ENSURE(m_ShaderProgram);
1245 0 : m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ);
1246 0 : }
1247 :
1248 0 : void CDeviceCommandContext::SetUniform(
1249 : const int32_t bindingSlot,
1250 : const float valueX, const float valueY,
1251 : const float valueZ, const float valueW)
1252 : {
1253 0 : ENSURE(m_ShaderProgram);
1254 0 : m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ, valueW);
1255 0 : }
1256 :
1257 0 : void CDeviceCommandContext::SetUniform(
1258 : const int32_t bindingSlot, PS::span<const float> values)
1259 : {
1260 0 : ENSURE(m_ShaderProgram);
1261 0 : m_ShaderProgram->SetUniform(bindingSlot, values);
1262 0 : }
1263 :
1264 0 : CDeviceCommandContext::ScopedBind::ScopedBind(
1265 : CDeviceCommandContext* deviceCommandContext,
1266 0 : const GLenum target, const GLuint handle)
1267 : : m_DeviceCommandContext(deviceCommandContext),
1268 0 : m_OldBindUnit(deviceCommandContext->m_BoundTextures[deviceCommandContext->m_ActiveTextureUnit]),
1269 0 : m_ActiveTextureUnit(deviceCommandContext->m_ActiveTextureUnit)
1270 : {
1271 0 : const uint32_t unit = m_DeviceCommandContext->m_BoundTextures.size() - 1;
1272 0 : m_DeviceCommandContext->BindTexture(unit, target, handle);
1273 0 : }
1274 :
1275 0 : CDeviceCommandContext::ScopedBind::~ScopedBind()
1276 : {
1277 0 : m_DeviceCommandContext->BindTexture(
1278 : m_ActiveTextureUnit, m_OldBindUnit.target, m_OldBindUnit.handle);
1279 0 : }
1280 :
1281 0 : CDeviceCommandContext::ScopedBufferBind::ScopedBufferBind(
1282 0 : CDeviceCommandContext* deviceCommandContext, CBuffer* buffer)
1283 0 : : m_DeviceCommandContext(deviceCommandContext)
1284 : {
1285 0 : ENSURE(buffer);
1286 0 : m_CacheIndex = static_cast<size_t>(buffer->GetType());
1287 0 : const GLenum target = BufferTypeToGLTarget(buffer->GetType());
1288 0 : const GLuint handle = buffer->GetHandle();
1289 0 : if (m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].first == target &&
1290 0 : m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].second == handle)
1291 : {
1292 : // Use an invalid index as a sign that we don't need to restore the
1293 : // bound buffer.
1294 0 : m_CacheIndex = m_DeviceCommandContext->m_BoundBuffers.size();
1295 : }
1296 : else
1297 : {
1298 0 : glBindBufferARB(target, handle);
1299 : }
1300 0 : }
1301 :
1302 0 : CDeviceCommandContext::ScopedBufferBind::~ScopedBufferBind()
1303 : {
1304 0 : if (m_CacheIndex >= m_DeviceCommandContext->m_BoundBuffers.size())
1305 0 : return;
1306 0 : glBindBufferARB(
1307 0 : m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].first,
1308 0 : m_DeviceCommandContext->m_BoundBuffers[m_CacheIndex].second);
1309 0 : }
1310 :
1311 : } // namespace GL
1312 :
1313 : } // namespace Backend
1314 :
1315 3 : } // namespace Renderer
|