LCOV - code coverage report
Current view: top level - source/renderer/backend/gl - DeviceCommandContext.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 727 0.1 %
Date: 2023-01-19 00:18:29 Functions: 2 61 3.3 %

          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

Generated by: LCOV version 1.13