1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "BsGLRenderAPI.h"
4#include "RenderAPI/BsRenderAPI.h"
5#include "BsGLTextureManager.h"
6#include "BsGLIndexBuffer.h"
7#include "BsGLUtil.h"
8#include "GLSL/BsGLSLGpuProgram.h"
9#include "Error/BsException.h"
10#include "BsGLContext.h"
11#include "BsGLSupport.h"
12#include "RenderAPI/BsBlendState.h"
13#include "RenderAPI/BsRasterizerState.h"
14#include "RenderAPI/BsDepthStencilState.h"
15#include "BsGLRenderTexture.h"
16#include "BsGLRenderWindowManager.h"
17#include "GLSL/BsGLSLProgramPipelineManager.h"
18#include "BsGLVertexArrayObjectManager.h"
19#include "Managers/BsRenderStateManager.h"
20#include "RenderAPI/BsGpuParams.h"
21#include "BsGLGpuParamBlockBuffer.h"
22#include "CoreThread/BsCoreThread.h"
23#include "BsGLQueryManager.h"
24#include "Debug/BsDebug.h"
25#include "Profiling/BsRenderStats.h"
26#include "RenderAPI/BsGpuParamDesc.h"
27#include "BsGLGpuBuffer.h"
28#include "BsGLCommandBuffer.h"
29#include "BsGLCommandBufferManager.h"
30#include "BsGLTextureView.h"
31#include "GLSL/BsGLSLParamParser.h"
32
33namespace bs { namespace ct
34{
35 const char* MODULE_NAME = "bsfGLRenderAPI.dll";
36
37 const char* bs_get_gl_error_string(GLenum errorCode)
38 {
39 switch (errorCode)
40 {
41 case GL_INVALID_OPERATION: return "INVALID_OPERATION";
42 case GL_INVALID_ENUM: return "INVALID_ENUM";
43 case GL_INVALID_VALUE: return "INVALID_VALUE";
44 case GL_OUT_OF_MEMORY: return "OUT_OF_MEMORY";
45 case GL_INVALID_FRAMEBUFFER_OPERATION: return "INVALID_FRAMEBUFFER_OPERATION";
46 }
47
48 return nullptr;
49 }
50
51 void bs_check_gl_error(const char* function, const char* file, INT32 line)
52 {
53 GLenum errorCode = glGetError();
54 if (errorCode != GL_NO_ERROR)
55 {
56 StringStream errorOutput;
57 errorOutput << "OpenGL error in " << function << " [" << file << ":" << toString(line) << "]:\n";
58
59 while (errorCode != GL_NO_ERROR)
60 {
61 const char* errorString = bs_get_gl_error_string(errorCode);
62 if (errorString)
63 errorOutput << "\t - " << errorString;
64
65 errorCode = glGetError();
66 }
67
68 gDebug().logWarning(errorOutput.str());
69 }
70 }
71
72#if BS_OPENGL_4_3 || BS_OPENGLES_3_2
73 void openGlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar
74 *message, GLvoid *userParam);
75#endif
76
77 /************************************************************************/
78 /* PUBLIC INTERFACE */
79 /************************************************************************/
80
81 GLRenderAPI::GLRenderAPI()
82 {
83 // Get our GLSupport
84 mGLSupport = ct::getGLSupport();
85
86 mColorWrite[0] = mColorWrite[1] = mColorWrite[2] = mColorWrite[3] = true;
87
88 mCurrentContext = 0;
89 mMainContext = 0;
90
91 mGLInitialised = false;
92
93 mMinFilter = FO_LINEAR;
94 mMipFilter = FO_POINT;
95
96 mProgramPipelineManager = bs_new<GLSLProgramPipelineManager>();
97 }
98
99 const StringID& GLRenderAPI::getName() const
100 {
101 static StringID strName("GLRenderAPI");
102 return strName;
103 }
104
105 void GLRenderAPI::initialize()
106 {
107 THROW_IF_NOT_CORE_THREAD;
108
109 mGLSupport->start();
110 mVideoModeInfo = mGLSupport->getVideoModeInfo();
111
112 CommandBufferManager::startUp<GLCommandBufferManager>();
113 bs::RenderWindowManager::startUp<bs::GLRenderWindowManager>(this);
114 RenderWindowManager::startUp();
115
116 RenderStateManager::startUp();
117
118 QueryManager::startUp<GLQueryManager>();
119
120 RenderAPI::initialize();
121 }
122
123 void GLRenderAPI::initializeWithWindow(const SPtr<RenderWindow>& primaryWindow)
124 {
125 // Get the context from the window and finish initialization
126 SPtr<GLContext> context;
127 primaryWindow->getCustomAttribute("GLCONTEXT", &context);
128
129 // Set main and current context
130 mMainContext = context;
131 mCurrentContext = mMainContext;
132
133 // Set primary context as active
134 if (mCurrentContext)
135 mCurrentContext->setCurrent(*primaryWindow);
136
137 // Setup GLSupport
138 mGLSupport->initializeExtensions();
139
140 mNumDevices = 1;
141 mCurrentCapabilities = bs_newN<RenderAPICapabilities>(mNumDevices);
142 initCapabilities(mCurrentCapabilities[0]);
143
144 initFromCaps(mCurrentCapabilities);
145 GLVertexArrayObjectManager::startUp();
146
147 glFrontFace(GL_CW);
148 BS_CHECK_GL_ERROR();
149
150 // Ensure cubemaps are filtered across seams
151 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
152 BS_CHECK_GL_ERROR();
153
154 GPUInfo gpuInfo;
155 gpuInfo.numGPUs = 1;
156
157 const char* vendor = (const char*)glGetString(GL_VENDOR);
158 BS_CHECK_GL_ERROR();
159
160 const char* renderer = (const char*)glGetString(GL_RENDERER);
161 BS_CHECK_GL_ERROR();
162
163 gpuInfo.names[0] = String(vendor) + " " + String(renderer);
164
165 PlatformUtility::_setGPUInfo(gpuInfo);
166
167 mGLInitialised = true;
168
169 RenderAPI::initializeWithWindow(primaryWindow);
170 }
171
172 void GLRenderAPI::destroyCore()
173 {
174 RenderAPI::destroyCore();
175
176 // Deleting the GLSL program factory
177 if (mGLSLProgramFactory)
178 {
179 // Remove from manager safely
180 GpuProgramManager::instance().removeFactory("glsl");
181 GpuProgramManager::instance().removeFactory("glsl4_1");
182
183 bs_delete(mGLSLProgramFactory);
184 mGLSLProgramFactory = nullptr;
185 }
186
187 // Deleting the hardware buffer manager. Has to be done before the mGLSupport->stop().
188 HardwareBufferManager::shutDown();
189 bs::HardwareBufferManager::shutDown();
190 GLRTTManager::shutDown();
191
192 for (UINT32 i = 0; i < MAX_VB_COUNT; i++)
193 mBoundVertexBuffers[i] = nullptr;
194
195 mBoundVertexDeclaration = nullptr;
196 mBoundIndexBuffer = nullptr;
197
198 mCurrentVertexProgram = nullptr;
199 mCurrentFragmentProgram = nullptr;
200 mCurrentGeometryProgram = nullptr;
201 mCurrentHullProgram = nullptr;
202 mCurrentDomainProgram = nullptr;
203 mCurrentComputeProgram = nullptr;
204
205 if (mGLSupport)
206 mGLSupport->stop();
207
208 TextureManager::shutDown();
209 bs::TextureManager::shutDown();
210 QueryManager::shutDown();
211 RenderWindowManager::shutDown();
212 bs::RenderWindowManager::shutDown();
213 RenderStateManager::shutDown();
214 GLVertexArrayObjectManager::shutDown(); // Note: Needs to be after QueryManager shutdown as some resources might be waiting for queries to complete
215 CommandBufferManager::shutDown();
216
217 mGLInitialised = false;
218
219 if(mProgramPipelineManager != nullptr)
220 bs_delete(mProgramPipelineManager);
221
222 if(mCurrentContext)
223 mCurrentContext->endCurrent();
224
225 mCurrentContext = nullptr;
226 mMainContext = nullptr;
227
228 if(mGLSupport)
229 bs_delete(mGLSupport);
230
231 if (mTextureInfos != nullptr)
232 bs_deleteN(mTextureInfos, mNumTextureUnits);
233 }
234
235 void GLRenderAPI::setGraphicsPipeline(const SPtr<GraphicsPipelineState>& pipelineState,
236 const SPtr<CommandBuffer>& commandBuffer)
237 {
238 auto executeRef = [&](const SPtr<GraphicsPipelineState>& pipelineState)
239 {
240 THROW_IF_NOT_CORE_THREAD;
241
242 BlendState* blendState;
243 RasterizerState* rasterizerState;
244 DepthStencilState* depthStencilState;
245 if (pipelineState != nullptr)
246 {
247 mCurrentVertexProgram = std::static_pointer_cast<GLSLGpuProgram>(pipelineState->getVertexProgram());
248 mCurrentFragmentProgram = std::static_pointer_cast<GLSLGpuProgram>(pipelineState->getFragmentProgram());
249 mCurrentGeometryProgram = std::static_pointer_cast<GLSLGpuProgram>(pipelineState->getGeometryProgram());
250 mCurrentDomainProgram = std::static_pointer_cast<GLSLGpuProgram>(pipelineState->getDomainProgram());
251 mCurrentHullProgram = std::static_pointer_cast<GLSLGpuProgram>(pipelineState->getHullProgram());
252
253 blendState = pipelineState->getBlendState().get();
254 rasterizerState = pipelineState->getRasterizerState().get();
255 depthStencilState = pipelineState->getDepthStencilState().get();
256
257 if (blendState == nullptr)
258 blendState = BlendState::getDefault().get();
259
260 if (rasterizerState == nullptr)
261 rasterizerState = RasterizerState::getDefault().get();
262
263 if(depthStencilState == nullptr)
264 depthStencilState = DepthStencilState::getDefault().get();
265 }
266 else
267 {
268 mCurrentVertexProgram = nullptr;
269 mCurrentFragmentProgram = nullptr;
270 mCurrentGeometryProgram = nullptr;
271 mCurrentDomainProgram = nullptr;
272 mCurrentHullProgram = nullptr;
273
274 blendState = BlendState::getDefault().get();
275 rasterizerState = RasterizerState::getDefault().get();
276 depthStencilState = DepthStencilState::getDefault().get();
277 }
278
279 // Blend state
280 {
281 const BlendProperties& stateProps = blendState->getProperties();
282
283 // Alpha to coverage
284 setAlphaToCoverage(stateProps.getAlphaToCoverageEnabled());
285
286 // Blend states
287 // OpenGL doesn't allow us to specify blend state per render target, so we just use the first one.
288 if (stateProps.getBlendEnabled(0))
289 {
290 setSceneBlending(stateProps.getSrcBlend(0), stateProps.getDstBlend(0), stateProps.getAlphaSrcBlend(0),
291 stateProps.getAlphaDstBlend(0), stateProps.getBlendOperation(0), stateProps.getAlphaBlendOperation(0));
292 }
293 else
294 {
295 setSceneBlending(BF_ONE, BF_ZERO, BO_ADD);
296 }
297
298 // Color write mask
299 UINT8 writeMask = stateProps.getRenderTargetWriteMask(0);
300 setColorBufferWriteEnabled((writeMask & 0x1) != 0, (writeMask & 0x2) != 0, (writeMask & 0x4) != 0, (writeMask & 0x8) != 0);
301 }
302
303 // Rasterizer state
304 {
305 const RasterizerProperties& stateProps = rasterizerState->getProperties();
306
307 setDepthBias(stateProps.getDepthBias(), stateProps.getSlopeScaledDepthBias());
308 setCullingMode(stateProps.getCullMode());
309 setPolygonMode(stateProps.getPolygonMode());
310 setScissorTestEnable(stateProps.getScissorEnable());
311 setMultisamplingEnable(stateProps.getMultisampleEnable());
312 setDepthClipEnable(stateProps.getDepthClipEnable());
313 setAntialiasedLineEnable(stateProps.getAntialiasedLineEnable());
314 }
315
316 // Depth stencil state
317 {
318 const DepthStencilProperties& stateProps = depthStencilState->getProperties();
319
320 // Set stencil buffer options
321 setStencilCheckEnabled(stateProps.getStencilEnable());
322
323 setStencilBufferOperations(stateProps.getStencilFrontFailOp(), stateProps.getStencilFrontZFailOp(),
324 stateProps.getStencilFrontPassOp(), true);
325 setStencilBufferFunc(stateProps.getStencilFrontCompFunc(), stateProps.getStencilReadMask(), true);
326
327 setStencilBufferOperations(stateProps.getStencilBackFailOp(), stateProps.getStencilBackZFailOp(),
328 stateProps.getStencilBackPassOp(), false);
329 setStencilBufferFunc(stateProps.getStencilBackCompFunc(), stateProps.getStencilReadMask(), false);
330
331 setStencilBufferWriteMask(stateProps.getStencilWriteMask());
332
333 // Set depth buffer options
334 setDepthBufferCheckEnabled(stateProps.getDepthReadEnable());
335 setDepthBufferWriteEnabled(stateProps.getDepthWriteEnable());
336 setDepthBufferFunction(stateProps.getDepthComparisonFunc());
337 }
338 };
339
340 if (commandBuffer == nullptr)
341 executeRef(pipelineState);
342 else
343 {
344 auto execute = [=]() { executeRef(pipelineState); };
345
346 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
347 cb->queueCommand(execute);
348 }
349
350 BS_INC_RENDER_STAT(NumPipelineStateChanges);
351 }
352
353 void GLRenderAPI::setComputePipeline(const SPtr<ComputePipelineState>& pipelineState,
354 const SPtr<CommandBuffer>& commandBuffer)
355 {
356 auto executeRef = [&](const SPtr<ComputePipelineState>& pipelineState)
357 {
358 THROW_IF_NOT_CORE_THREAD;
359
360 SPtr<GpuProgram> program;
361 if (pipelineState != nullptr)
362 program = pipelineState->getProgram();
363
364 if (program != nullptr && program->getType() == GPT_COMPUTE_PROGRAM)
365 mCurrentComputeProgram = std::static_pointer_cast<GLSLGpuProgram>(program);
366 else
367 mCurrentComputeProgram = nullptr;
368 };
369
370 if (commandBuffer == nullptr)
371 executeRef(pipelineState);
372 else
373 {
374 auto execute = [=]() { executeRef(pipelineState); };
375
376 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
377 cb->queueCommand(execute);
378 }
379
380 BS_INC_RENDER_STAT(NumPipelineStateChanges);
381 }
382
383 void GLRenderAPI::setGpuParams(const SPtr<GpuParams>& gpuParams, const SPtr<CommandBuffer>& commandBuffer)
384 {
385 auto executeRef = [&](const SPtr<GpuParams>& gpuParams)
386 {
387 THROW_IF_NOT_CORE_THREAD;
388
389#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
390 for (UINT32 i = 0; i < 8; i++)
391 {
392 glBindImageTexture(i, 0, 0, false, 0, GL_READ_WRITE, GL_R32F);
393 BS_CHECK_GL_ERROR();
394 }
395#endif
396
397 bs_frame_mark();
398 {
399 FrameVector<UINT32> textureUnits;
400 textureUnits.reserve(12);
401
402 auto getTexUnit = [&](UINT32 binding)
403 {
404 for(UINT32 i = 0; i < (UINT32)textureUnits.size(); i++)
405 {
406 if (textureUnits[i] == binding)
407 return i;
408 }
409
410 UINT32 unit = (UINT32)textureUnits.size();
411 textureUnits.push_back(binding);
412
413 return unit;
414 };
415
416#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
417 UINT32 imageUnitCount = 0;
418 auto getImageUnit = [&](UINT32 binding)
419 {
420 return imageUnitCount++;
421 };
422#endif
423
424 UINT32 uniformUnitCount = 0;
425 auto getUniformUnit = [&](UINT32 binding)
426 {
427 return uniformUnitCount++;
428 };
429
430#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
431 UINT32 sharedStorageUnitCount = 0;
432 auto getSharedStorageUnit = [&](UINT32 binding)
433 {
434 return sharedStorageUnitCount++;
435 };
436#endif
437
438 const UINT32 numStages = 6;
439 for(UINT32 i = 0; i < numStages; i++)
440 {
441 for(auto& entry : textureUnits)
442 entry = (UINT32)-1;
443
444 GpuProgramType type = (GpuProgramType)i;
445
446 SPtr<GpuParamDesc> paramDesc = gpuParams->getParamDesc(type);
447 if (paramDesc == nullptr)
448 continue;
449
450 for (auto& entry : paramDesc->textures)
451 {
452 UINT32 binding = entry.second.slot;
453 SPtr<Texture> texture = gpuParams->getTexture(entry.second.set, binding);
454 const TextureSurface& surface = gpuParams->getTextureSurface(entry.second.set, binding);
455
456 UINT32 unit = getTexUnit(binding);
457 if (!activateGLTextureUnit(unit))
458 continue;
459
460 TextureInfo& texInfo = mTextureInfos[unit];
461
462 GLTexture* glTex = static_cast<GLTexture*>(texture.get());
463 GLenum newTextureType;
464 GLuint texId;
465 if (glTex != nullptr)
466 {
467#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
468 SPtr<TextureView> texView = glTex->requestView(
469 surface.mipLevel,
470 surface.numMipLevels,
471 surface.face,
472 surface.numFaces,
473 GVU_DEFAULT);
474
475 GLTextureView* glTexView = static_cast<GLTextureView*>(texView.get());
476
477 newTextureType = glTexView->getGLTextureTarget();
478 texId = glTexView->getGLID();
479#else
480 // Texture views are not supported, so if user requested a part of the texture surface report
481 // a warning
482 auto& props = texture->getProperties();
483 if (surface.mipLevel != 0 || surface.face != 0 ||
484 (surface.numMipLevels != 0 && surface.numMipLevels != props.getNumMipmaps()) ||
485 (surface.numFaces != 0 && surface.numFaces != props.getNumFaces()))
486 {
487 LOGWRN("Attempting to bind only a part of a texture, but texture views are not supported. "
488 "Entire texture will be bound instead.");
489 }
490
491 newTextureType = glTex->getGLTextureTarget();
492 texId = glTex->getGLID();
493#endif
494 }
495 else
496 {
497
498 newTextureType = GLTexture::getGLTextureTarget(entry.second.type);
499 texId = 0;
500 }
501
502 if (texInfo.type != newTextureType)
503 {
504 glBindTexture(texInfo.type, 0);
505 BS_CHECK_GL_ERROR();
506 }
507
508 glBindTexture(newTextureType, texId);
509 BS_CHECK_GL_ERROR();
510
511 texInfo.type = newTextureType;
512
513 SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
514 if (activeProgram != nullptr)
515 {
516 GLuint glProgram = activeProgram->getGLHandle();
517
518 glProgramUniform1i(glProgram, binding, unit);
519 BS_CHECK_GL_ERROR();
520 }
521 }
522
523 for(auto& entry : paramDesc->samplers)
524 {
525 UINT32 binding = entry.second.slot;
526 SPtr<SamplerState> samplerState = gpuParams->getSamplerState(entry.second.set, binding);
527
528 if (samplerState == nullptr)
529 samplerState = SamplerState::getDefault();
530
531 UINT32 unit = getTexUnit(binding);
532 if (!activateGLTextureUnit(unit))
533 continue;
534
535 // No sampler options for multisampled textures or buffers
536 bool supportsSampler = mTextureInfos[unit].type != GL_TEXTURE_2D_MULTISAMPLE &&
537 mTextureInfos[unit].type != GL_TEXTURE_2D_MULTISAMPLE_ARRAY &&
538 mTextureInfos[unit].type != GL_TEXTURE_BUFFER;
539
540 if (supportsSampler)
541 {
542 const SamplerProperties& stateProps = samplerState->getProperties();
543
544 setTextureFiltering(unit, FT_MIN, stateProps.getTextureFiltering(FT_MIN));
545 setTextureFiltering(unit, FT_MAG, stateProps.getTextureFiltering(FT_MAG));
546 setTextureFiltering(unit, FT_MIP, stateProps.getTextureFiltering(FT_MIP));
547
548 setTextureAnisotropy(unit, stateProps.getTextureAnisotropy());
549 setTextureCompareMode(unit, stateProps.getComparisonFunction());
550
551 setTextureMipmapBias(unit, stateProps.getTextureMipmapBias());
552 setTextureMipmapRange(unit, stateProps.getMinimumMip(), stateProps.getMaximumMip());
553
554 const UVWAddressingMode& uvw = stateProps.getTextureAddressingMode();
555 setTextureAddressingMode(unit, uvw);
556
557 setTextureBorderColor(unit, stateProps.getBorderColor());
558 }
559 }
560
561 for(auto& entry : paramDesc->buffers)
562 {
563 UINT32 binding = entry.second.slot;
564 SPtr<GpuBuffer> buffer = gpuParams->getBuffer(entry.second.set, binding);
565
566 GLGpuBuffer* glBuffer = static_cast<GLGpuBuffer*>(buffer.get());
567
568 switch(entry.second.type)
569 {
570 case GPOT_BYTE_BUFFER: // Texture buffer (read-only, unstructured)
571 {
572 UINT32 unit = getTexUnit(binding);
573 if (!activateGLTextureUnit(unit))
574 continue;
575
576 GLuint texId = 0;
577 if (glBuffer != nullptr)
578 texId = glBuffer->getGLTextureId();
579
580 if (mTextureInfos[unit].type != GL_TEXTURE_BUFFER)
581 {
582 glBindTexture(mTextureInfos[unit].type, 0);
583 BS_CHECK_GL_ERROR();
584 }
585
586 mTextureInfos[unit].type = GL_TEXTURE_BUFFER;
587
588 glBindTexture(GL_TEXTURE_BUFFER, texId);
589 BS_CHECK_GL_ERROR();
590
591 SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
592 if (activeProgram != nullptr)
593 {
594 GLuint glProgram = activeProgram->getGLHandle();
595
596 glProgramUniform1i(glProgram, binding, unit);
597 BS_CHECK_GL_ERROR();
598 }
599 }
600 break;
601#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
602 case GPOT_RWBYTE_BUFFER: // Storage buffer (read/write, unstructured)
603 {
604 UINT32 unit = getImageUnit(binding);
605
606 GLuint texId = 0;
607 GLuint format = GL_R32F;
608 if (glBuffer != nullptr)
609 {
610 texId = glBuffer->getGLTextureId();
611 format = glBuffer->getGLFormat();
612 }
613
614 glBindImageTexture(unit, texId, 0, false, 0, GL_READ_WRITE, format);
615 BS_CHECK_GL_ERROR();
616
617 SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
618 if (activeProgram != nullptr)
619 {
620 GLuint glProgram = activeProgram->getGLHandle();
621
622 glProgramUniform1i(glProgram, binding, unit);
623 BS_CHECK_GL_ERROR();
624 }
625 }
626 break;
627#endif
628#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
629 case GPOT_RWSTRUCTURED_BUFFER: // Shared storage block (read/write, structured)
630 {
631 UINT32 unit = getSharedStorageUnit(binding);
632
633 GLuint bufferId = 0;
634 if (glBuffer != nullptr)
635 bufferId = glBuffer->getGLBufferId();
636
637 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, unit, bufferId);
638 BS_CHECK_GL_ERROR();
639
640 SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
641 if (activeProgram != nullptr)
642 {
643 GLuint glProgram = activeProgram->getGLHandle();
644
645 glShaderStorageBlockBinding(glProgram, binding, unit);
646 BS_CHECK_GL_ERROR();
647 }
648 }
649 break;
650#endif
651 default:
652 break;
653 }
654 }
655
656#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
657 for(auto& entry : paramDesc->loadStoreTextures)
658 {
659 UINT32 binding = entry.second.slot;
660
661 SPtr<Texture> texture = gpuParams->getLoadStoreTexture(entry.second.set, binding);
662 const TextureSurface& surface = gpuParams->getLoadStoreSurface(entry.second.set, binding);
663
664 UINT32 unit = getImageUnit(binding);
665 GLuint texId = 0;
666 UINT32 mipLevel = 0;
667 UINT32 face = 0;
668 bool bindAllLayers = false;
669 GLenum format = GL_R32F;
670
671 if (texture != nullptr)
672 {
673 GLTexture* tex = static_cast<GLTexture*>(texture.get());
674 auto& texProps = tex->getProperties();
675
676 bindAllLayers = texProps.getNumFaces() == surface.numFaces || surface.numFaces == 0;
677
678 if(!bindAllLayers && surface.numFaces > 1)
679 {
680 LOGWRN("Attempting to bind multiple faces of a load-store texture. You are allowed to bind \
681 either a single face, or all the faces of the texture. Only the first face will \
682 be bound instead.");
683 }
684
685 if(surface.numMipLevels > 1)
686 {
687 LOGWRN("Attempting to bind multiple mip levels of a load-store texture. This is not \
688 supported and only the first provided level will be bound.");
689 }
690
691 texId = tex->getGLID();
692 format = tex->getGLFormat();
693 mipLevel = surface.mipLevel;
694 face = surface.face;
695 }
696
697 glBindImageTexture(unit, texId, mipLevel, bindAllLayers, face, GL_READ_WRITE, format);
698 BS_CHECK_GL_ERROR();
699
700 SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
701 if (activeProgram != nullptr)
702 {
703 GLuint glProgram = activeProgram->getGLHandle();
704
705 glProgramUniform1i(glProgram, binding, unit);
706 BS_CHECK_GL_ERROR();
707 }
708 }
709#endif
710
711 for (auto& entry : paramDesc->paramBlocks)
712 {
713 UINT32 binding = entry.second.slot;
714 SPtr<GpuParamBlockBuffer> buffer = gpuParams->getParamBlockBuffer(entry.second.set, binding);
715
716 if (buffer == nullptr)
717 continue;
718
719 buffer->flushToGPU();
720
721 SPtr<GLSLGpuProgram> activeProgram = getActiveProgram(type);
722 GLuint glProgram = activeProgram->getGLHandle();
723
724 // 0 means uniforms are not in block, in which case we handle it specially
725 if (binding == 0)
726 {
727 UINT8* uniformBufferData = (UINT8*)bs_stack_alloc(buffer->getSize());
728 buffer->read(0, uniformBufferData, buffer->getSize());
729
730 for (auto iter = paramDesc->params.begin(); iter != paramDesc->params.end(); ++iter)
731 {
732 const GpuParamDataDesc& param = iter->second;
733
734 if (param.paramBlockSlot != 0) // 0 means uniforms are not in a block
735 continue;
736
737 const UINT8* ptrData = uniformBufferData + param.cpuMemOffset * sizeof(UINT32);
738
739 // Note: We don't transpose matrices here even though we don't use column major format
740 // because they are assumed to be pre-transposed in the GpuParams buffer
741 switch (param.type)
742 {
743 case GPDT_FLOAT1:
744 glProgramUniform1fv(glProgram, param.gpuMemOffset, param.arraySize, (GLfloat*)ptrData);
745 BS_CHECK_GL_ERROR();
746 break;
747 case GPDT_FLOAT2:
748 glProgramUniform2fv(glProgram, param.gpuMemOffset, param.arraySize, (GLfloat*)ptrData);
749 BS_CHECK_GL_ERROR();
750 break;
751 case GPDT_FLOAT3:
752 glProgramUniform3fv(glProgram, param.gpuMemOffset, param.arraySize, (GLfloat*)ptrData);
753 BS_CHECK_GL_ERROR();
754 break;
755 case GPDT_FLOAT4:
756 glProgramUniform4fv(glProgram, param.gpuMemOffset, param.arraySize, (GLfloat*)ptrData);
757 BS_CHECK_GL_ERROR();
758 break;
759 case GPDT_MATRIX_2X2:
760 glProgramUniformMatrix2fv(
761 glProgram,
762 param.gpuMemOffset,
763 param.arraySize,
764 GL_FALSE,
765 (GLfloat*)ptrData);
766 BS_CHECK_GL_ERROR();
767 break;
768 case GPDT_MATRIX_2X3:
769 glProgramUniformMatrix3x2fv(
770 glProgram,
771 param.gpuMemOffset,
772 param.arraySize,
773 GL_FALSE,
774 (GLfloat*)ptrData);
775 BS_CHECK_GL_ERROR();
776 break;
777 case GPDT_MATRIX_2X4:
778 glProgramUniformMatrix4x2fv(
779 glProgram,
780 param.gpuMemOffset,
781 param.arraySize,
782 GL_FALSE,
783 (GLfloat*)ptrData);
784 BS_CHECK_GL_ERROR();
785 break;
786 case GPDT_MATRIX_3X2:
787 glProgramUniformMatrix2x3fv(
788 glProgram,
789 param.gpuMemOffset,
790 param.arraySize,
791 GL_FALSE,
792 (GLfloat*)ptrData);
793 BS_CHECK_GL_ERROR();
794 break;
795 case GPDT_MATRIX_3X3:
796 glProgramUniformMatrix3fv(
797 glProgram,
798 param.gpuMemOffset,
799 param.arraySize,
800 GL_FALSE,
801 (GLfloat*)ptrData);
802 BS_CHECK_GL_ERROR();
803 break;
804 case GPDT_MATRIX_3X4:
805 glProgramUniformMatrix4x3fv(
806 glProgram,
807 param.gpuMemOffset,
808 param.arraySize,
809 GL_FALSE,
810 (GLfloat*)ptrData);
811 BS_CHECK_GL_ERROR();
812 break;
813 case GPDT_MATRIX_4X2:
814 glProgramUniformMatrix2x4fv(
815 glProgram,
816 param.gpuMemOffset,
817 param.arraySize,
818 GL_FALSE,
819 (GLfloat*)ptrData);
820 BS_CHECK_GL_ERROR();
821 break;
822 case GPDT_MATRIX_4X3:
823 glProgramUniformMatrix3x4fv(
824 glProgram,
825 param.gpuMemOffset,
826 param.arraySize,
827 GL_FALSE,
828 (GLfloat*)ptrData);
829 BS_CHECK_GL_ERROR();
830 break;
831 case GPDT_MATRIX_4X4:
832 glProgramUniformMatrix4fv(
833 glProgram,
834 param.gpuMemOffset,
835 param.arraySize,
836 GL_FALSE,
837 (GLfloat*)ptrData);
838 BS_CHECK_GL_ERROR();
839 break;
840 case GPDT_INT1:
841 glProgramUniform1iv(glProgram, param.gpuMemOffset, param.arraySize, (GLint*)ptrData);
842 BS_CHECK_GL_ERROR();
843 break;
844 case GPDT_INT2:
845 glProgramUniform2iv(glProgram, param.gpuMemOffset, param.arraySize, (GLint*)ptrData);
846 BS_CHECK_GL_ERROR();
847 break;
848 case GPDT_INT3:
849 glProgramUniform3iv(glProgram, param.gpuMemOffset, param.arraySize, (GLint*)ptrData);
850 BS_CHECK_GL_ERROR();
851 break;
852 case GPDT_INT4:
853 glProgramUniform4iv(glProgram, param.gpuMemOffset, param.arraySize, (GLint*)ptrData);
854 BS_CHECK_GL_ERROR();
855 break;
856 case GPDT_BOOL:
857 glProgramUniform1uiv(glProgram, param.gpuMemOffset, param.arraySize, (GLuint*)ptrData);
858 BS_CHECK_GL_ERROR();
859 break;
860 default:
861 case GPDT_UNKNOWN:
862 break;
863 }
864 }
865
866 if (uniformBufferData != nullptr)
867 bs_stack_free(uniformBufferData);
868 }
869 else
870 {
871 const GLGpuParamBlockBuffer* glParamBlockBuffer = static_cast<const GLGpuParamBlockBuffer*>(buffer.get());
872
873 UINT32 unit = getUniformUnit(binding - 1);
874 glUniformBlockBinding(glProgram, binding - 1, unit);
875 BS_CHECK_GL_ERROR();
876
877 glBindBufferBase(GL_UNIFORM_BUFFER, unit, glParamBlockBuffer->getGLBufferId());
878 BS_CHECK_GL_ERROR();
879 }
880 }
881 }
882 }
883 bs_frame_clear();
884
885 activateGLTextureUnit(0);
886 };
887
888 if (commandBuffer == nullptr)
889 executeRef(gpuParams);
890 else
891 {
892 auto execute = [=]() { executeRef(gpuParams); };
893
894 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
895 cb->queueCommand(execute);
896 }
897
898 BS_INC_RENDER_STAT(NumGpuParamBinds);
899 }
900
901 void GLRenderAPI::setStencilRef(UINT32 stencilRefValue, const SPtr<CommandBuffer>& commandBuffer)
902 {
903 auto executeRef = [&](UINT32 stencilRefValue)
904 {
905 THROW_IF_NOT_CORE_THREAD;
906
907 setStencilRefValue(stencilRefValue);
908 };
909
910 if (commandBuffer == nullptr)
911 executeRef(stencilRefValue);
912 else
913 {
914 auto execute = [=]() { executeRef(stencilRefValue); };
915
916 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
917 cb->queueCommand(execute);
918 }
919 }
920
921 void GLRenderAPI::setViewport(const Rect2& area,
922 const SPtr<CommandBuffer>& commandBuffer)
923 {
924 auto executeRef = [&](const Rect2& area)
925 {
926 THROW_IF_NOT_CORE_THREAD;
927
928 mViewportNorm = area;
929 applyViewport();
930 };
931
932 if (commandBuffer == nullptr)
933 executeRef(area);
934 else
935 {
936 auto execute = [=]() { executeRef(area); };
937
938 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
939 cb->queueCommand(execute);
940 }
941 }
942
943 void GLRenderAPI::setRenderTarget(const SPtr<RenderTarget>& target, UINT32 readOnlyFlags,
944 RenderSurfaceMask loadMask, const SPtr<CommandBuffer>& commandBuffer)
945 {
946 auto executeRef = [&](const SPtr<RenderTarget>& target, UINT32 readOnlyFlags)
947 {
948 THROW_IF_NOT_CORE_THREAD;
949
950 // Switch context if different from current one
951 if (target != nullptr && target->getProperties().isWindow)
952 {
953 RenderWindow* window = static_cast<RenderWindow*>(target.get());
954
955 SPtr<GLContext> newContext;
956 target->getCustomAttribute("GLCONTEXT", &newContext);
957 if (newContext && mCurrentContext != newContext)
958 switchContext(newContext, *window);
959 else
960 mCurrentContext->setCurrent(*window);
961 }
962
963 // This must happen after context switch to ensure previous context is still alive
964 mActiveRenderTarget = target;
965
966 GLFrameBufferObject* fbo = nullptr;
967
968 if (target != nullptr)
969 target->getCustomAttribute("FBO", &fbo);
970
971 if (fbo != nullptr)
972 {
973 fbo->bind();
974
975 // Enable / disable sRGB states
976 if (target->getProperties().hwGamma)
977 {
978 glEnable(GL_FRAMEBUFFER_SRGB);
979 BS_CHECK_GL_ERROR();
980 }
981 else
982 {
983 glDisable(GL_FRAMEBUFFER_SRGB);
984 BS_CHECK_GL_ERROR();
985 }
986 }
987 else
988 {
989 glBindFramebuffer(GL_FRAMEBUFFER, 0);
990 BS_CHECK_GL_ERROR();
991 }
992
993 applyViewport();
994 };
995
996 if (commandBuffer == nullptr)
997 executeRef(target, readOnlyFlags);
998 else
999 {
1000 auto execute = [=]() { executeRef(target, readOnlyFlags); };
1001
1002 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1003 cb->queueCommand(execute);
1004 }
1005
1006 BS_INC_RENDER_STAT(NumRenderTargetChanges);
1007 }
1008
1009 void GLRenderAPI::setVertexBuffers(UINT32 index, SPtr<VertexBuffer>* buffers, UINT32 numBuffers,
1010 const SPtr<CommandBuffer>& commandBuffer)
1011 {
1012#if BS_DEBUG_MODE
1013 UINT32 lastIdx = index + numBuffers;
1014 if(lastIdx > MAX_VB_COUNT)
1015 {
1016 LOGERR("Provided vertex buffer slot range is invalid: " + toString(index) + " to " +
1017 toString(index + numBuffers) + ".");
1018 return;
1019 }
1020#endif
1021
1022 auto executeRef = [&](UINT32 index, SPtr<VertexBuffer>* buffers, UINT32 numBuffers)
1023 {
1024 THROW_IF_NOT_CORE_THREAD;
1025
1026 std::array<SPtr<VertexBuffer>, MAX_VB_COUNT> boundBuffers;
1027 for (UINT32 i = 0; i < numBuffers; i++)
1028 boundBuffers[index + i] = buffers[i];
1029
1030 for (UINT32 i = 0; i < numBuffers; i++)
1031 mBoundVertexBuffers[index + i] = boundBuffers[index + i];
1032 };
1033
1034 if (commandBuffer == nullptr)
1035 executeRef(index, buffers, numBuffers);
1036 else
1037 {
1038 auto execute = [=]() { executeRef(index, buffers, numBuffers); };
1039
1040 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1041 cb->queueCommand(execute);
1042 }
1043 }
1044
1045 void GLRenderAPI::setVertexDeclaration(const SPtr<VertexDeclaration>& vertexDeclaration,
1046 const SPtr<CommandBuffer>& commandBuffer)
1047 {
1048 auto executeRef = [&](const SPtr<VertexDeclaration>& vertexDeclaration)
1049 {
1050 THROW_IF_NOT_CORE_THREAD;
1051
1052 mBoundVertexDeclaration = vertexDeclaration;
1053 };
1054
1055 if (commandBuffer == nullptr)
1056 executeRef(vertexDeclaration);
1057 else
1058 {
1059 auto execute = [=]() { executeRef(vertexDeclaration); };
1060
1061 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1062 cb->queueCommand(execute);
1063 }
1064 }
1065
1066 void GLRenderAPI::setDrawOperation(DrawOperationType op, const SPtr<CommandBuffer>& commandBuffer)
1067 {
1068 auto executeRef = [&](DrawOperationType op)
1069 {
1070 THROW_IF_NOT_CORE_THREAD;
1071
1072 mCurrentDrawOperation = op;
1073 };
1074
1075 if (commandBuffer == nullptr)
1076 executeRef(op);
1077 else
1078 {
1079 auto execute = [=]() { executeRef(op); };
1080
1081 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1082 cb->queueCommand(execute);
1083
1084 cb->mCurrentDrawOperation = op;
1085 }
1086 }
1087
1088 void GLRenderAPI::setIndexBuffer(const SPtr<IndexBuffer>& buffer, const SPtr<CommandBuffer>& commandBuffer)
1089 {
1090 auto executeRef = [&](const SPtr<IndexBuffer>& buffer)
1091 {
1092 THROW_IF_NOT_CORE_THREAD;
1093
1094 mBoundIndexBuffer = buffer;
1095 };
1096
1097 if (commandBuffer == nullptr)
1098 executeRef(buffer);
1099 else
1100 {
1101 auto execute = [=]() { executeRef(buffer); };
1102
1103 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1104 cb->queueCommand(execute);
1105 }
1106 }
1107
1108 void GLRenderAPI::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount,
1109 const SPtr<CommandBuffer>& commandBuffer)
1110 {
1111 auto executeRef = [&](UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount)
1112 {
1113 THROW_IF_NOT_CORE_THREAD;
1114
1115 // Find the correct type to render
1116 GLint primType = getGLDrawMode();
1117 beginDraw();
1118
1119 if (instanceCount <= 1)
1120 {
1121 glDrawArrays(primType, vertexOffset, vertexCount);
1122 BS_CHECK_GL_ERROR();
1123 }
1124 else
1125 {
1126 glDrawArraysInstanced(primType, vertexOffset, vertexCount, instanceCount);
1127 BS_CHECK_GL_ERROR();
1128 }
1129
1130 endDraw();
1131 };
1132
1133 UINT32 primCount;
1134 if (commandBuffer == nullptr)
1135 {
1136 executeRef(vertexOffset, vertexCount, instanceCount);
1137
1138 primCount = vertexCountToPrimCount(mCurrentDrawOperation, vertexCount);
1139 }
1140 else
1141 {
1142 auto execute = [=]() { executeRef(vertexOffset, vertexCount, instanceCount); };
1143
1144 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1145 cb->queueCommand(execute);
1146
1147 primCount = vertexCountToPrimCount(cb->mCurrentDrawOperation, vertexCount);
1148 }
1149
1150 BS_INC_RENDER_STAT(NumDrawCalls);
1151 BS_ADD_RENDER_STAT(NumVertices, vertexCount);
1152 BS_ADD_RENDER_STAT(NumPrimitives, primCount);
1153 }
1154
1155 void GLRenderAPI::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount,
1156 UINT32 instanceCount, const SPtr<CommandBuffer>& commandBuffer)
1157 {
1158 auto executeRef = [&](UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount,
1159 UINT32 instanceCount)
1160 {
1161 THROW_IF_NOT_CORE_THREAD;
1162
1163 if (mBoundIndexBuffer == nullptr)
1164 {
1165 LOGWRN("Cannot draw indexed because index buffer is not set.");
1166 return;
1167 }
1168
1169 // Find the correct type to render
1170 GLint primType = getGLDrawMode();
1171
1172 beginDraw();
1173
1174 SPtr<GLIndexBuffer> indexBuffer = std::static_pointer_cast<GLIndexBuffer>(mBoundIndexBuffer);
1175 const IndexBufferProperties& ibProps = indexBuffer->getProperties();
1176 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->getGLBufferId());
1177 BS_CHECK_GL_ERROR();
1178
1179 GLenum indexType = (ibProps.getType() == IT_16BIT) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
1180
1181 if (instanceCount <= 1)
1182 {
1183 glDrawElementsBaseVertex(
1184 primType,
1185 indexCount,
1186 indexType,
1187 (GLvoid*)(UINT64)(ibProps.getIndexSize() * startIndex),
1188 vertexOffset);
1189 BS_CHECK_GL_ERROR();
1190 }
1191 else
1192 {
1193 glDrawElementsInstancedBaseVertex(
1194 primType,
1195 indexCount,
1196 indexType,
1197 (GLvoid*)(UINT64)(ibProps.getIndexSize() * startIndex),
1198 instanceCount,
1199 vertexOffset);
1200 BS_CHECK_GL_ERROR();
1201 }
1202
1203 endDraw();
1204 };
1205
1206 UINT32 primCount;
1207 if (commandBuffer == nullptr)
1208 {
1209 executeRef(startIndex, indexCount, vertexOffset, vertexCount, instanceCount);
1210
1211 primCount = vertexCountToPrimCount(mCurrentDrawOperation, vertexCount);
1212 }
1213 else
1214 {
1215 auto execute = [=]() { executeRef(startIndex, indexCount, vertexOffset, vertexCount, instanceCount); };
1216
1217 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1218 cb->queueCommand(execute);
1219
1220 primCount = vertexCountToPrimCount(cb->mCurrentDrawOperation, vertexCount);
1221 }
1222
1223 BS_INC_RENDER_STAT(NumDrawCalls);
1224 BS_ADD_RENDER_STAT(NumVertices, vertexCount);
1225 BS_ADD_RENDER_STAT(NumPrimitives, primCount);
1226
1227 BS_INC_RENDER_STAT(NumIndexBufferBinds);
1228 }
1229
1230 void GLRenderAPI::dispatchCompute(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ,
1231 const SPtr<CommandBuffer>& commandBuffer)
1232 {
1233 auto executeRef = [&](UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ)
1234 {
1235 THROW_IF_NOT_CORE_THREAD;
1236
1237 if (mCurrentComputeProgram == nullptr)
1238 {
1239 LOGWRN("Cannot dispatch compute without a set compute program.");
1240 return;
1241 }
1242
1243#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
1244 glUseProgram(mCurrentComputeProgram->getGLHandle());
1245 BS_CHECK_GL_ERROR();
1246
1247 glDispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
1248 BS_CHECK_GL_ERROR();
1249
1250 glMemoryBarrier(GL_ALL_BARRIER_BITS);
1251#else
1252 LOGWRN("Compute shaders not supported on current OpenGL version.");
1253#endif
1254 };
1255
1256 if (commandBuffer == nullptr)
1257 executeRef(numGroupsX, numGroupsY, numGroupsZ);
1258 else
1259 {
1260 auto execute = [=]() { executeRef(numGroupsX, numGroupsY, numGroupsZ); };
1261
1262 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1263 cb->queueCommand(execute);
1264 }
1265
1266 BS_INC_RENDER_STAT(NumComputeCalls);
1267 }
1268
1269 void GLRenderAPI::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom,
1270 const SPtr<CommandBuffer>& commandBuffer)
1271 {
1272 auto executeRef = [&](UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
1273 {
1274 THROW_IF_NOT_CORE_THREAD;
1275
1276 mScissorTop = top;
1277 mScissorBottom = bottom;
1278 mScissorLeft = left;
1279 mScissorRight = right;
1280 };
1281
1282 if (commandBuffer == nullptr)
1283 executeRef(left, top, right, bottom);
1284 else
1285 {
1286 auto execute = [=]() { executeRef(left, top, right, bottom); };
1287
1288 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1289 cb->queueCommand(execute);
1290 }
1291 }
1292
1293 void GLRenderAPI::clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask,
1294 const SPtr<CommandBuffer>& commandBuffer)
1295 {
1296 auto executeRef = [&](UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
1297 {
1298 if (mActiveRenderTarget == nullptr)
1299 return;
1300
1301 const RenderTargetProperties& rtProps = mActiveRenderTarget->getProperties();
1302 Rect2I clearRect(0, 0, rtProps.width, rtProps.height);
1303
1304 clearArea(buffers, color, depth, stencil, clearRect, targetMask);
1305 };
1306
1307 if (commandBuffer == nullptr)
1308 executeRef(buffers, color, depth, stencil, targetMask);
1309 else
1310 {
1311 auto execute = [=]() { executeRef(buffers, color, depth, stencil, targetMask); };
1312
1313 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1314 cb->queueCommand(execute);
1315 }
1316 }
1317
1318 void GLRenderAPI::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask,
1319 const SPtr<CommandBuffer>& commandBuffer)
1320 {
1321 auto executeRef = [&](UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
1322 {
1323 Rect2I clearRect(mViewportLeft, mViewportTop, mViewportWidth, mViewportHeight);
1324
1325 clearArea(buffers, color, depth, stencil, clearRect, targetMask);
1326 };
1327
1328 if (commandBuffer == nullptr)
1329 executeRef(buffers, color, depth, stencil, targetMask);
1330 else
1331 {
1332 auto execute = [=]() { executeRef(buffers, color, depth, stencil, targetMask); };
1333
1334 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1335 cb->queueCommand(execute);
1336 }
1337 }
1338
1339 void GLRenderAPI::swapBuffers(const SPtr<RenderTarget>& target, UINT32 syncMask)
1340 {
1341 THROW_IF_NOT_CORE_THREAD;
1342
1343 // Switch context if different from current one
1344 if(!target->getProperties().isWindow)
1345 return;
1346
1347 RenderWindow* window = static_cast<RenderWindow*>(target.get());
1348
1349 SPtr<GLContext> newContext;
1350 target->getCustomAttribute("GLCONTEXT", &newContext);
1351 if (newContext && mCurrentContext != newContext)
1352 switchContext(newContext, *window);
1353 else
1354 mCurrentContext->setCurrent(*window);
1355
1356 target->swapBuffers();
1357
1358 BS_INC_RENDER_STAT(NumPresents);
1359 }
1360
1361 void GLRenderAPI::addCommands(const SPtr<CommandBuffer>& commandBuffer, const SPtr<CommandBuffer>& secondary)
1362 {
1363 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1364 SPtr<GLCommandBuffer> secondaryCb = std::static_pointer_cast<GLCommandBuffer>(secondary);
1365
1366 cb->appendSecondary(secondaryCb);
1367 }
1368
1369 void GLRenderAPI::submitCommandBuffer(const SPtr<CommandBuffer>& commandBuffer, UINT32 syncMask)
1370 {
1371 SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
1372 if (cb == nullptr)
1373 return;
1374
1375 cb->executeCommands();
1376 cb->clear();
1377 }
1378
1379 void GLRenderAPI::clearArea(UINT32 buffers, const Color& color, float depth, UINT16 stencil, const Rect2I& clearRect,
1380 UINT8 targetMask)
1381 {
1382 THROW_IF_NOT_CORE_THREAD;
1383
1384 if(mActiveRenderTarget == nullptr)
1385 return;
1386
1387 bool colorMask = !mColorWrite[0] || !mColorWrite[1] || !mColorWrite[2] || !mColorWrite[3];
1388
1389 // Disable scissor test as we want to clear the entire render surface
1390 GLboolean scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST);
1391 UINT32 oldScissorTop = mScissorTop;
1392 UINT32 oldScissorBottom = mScissorBottom;
1393 UINT32 oldScissorLeft = mScissorLeft;
1394 UINT32 oldScissorRight = mScissorRight;
1395
1396 if (scissorTestEnabled)
1397 {
1398 glDisable(GL_SCISSOR_TEST);
1399 BS_CHECK_GL_ERROR();
1400 }
1401
1402 const RenderTargetProperties& rtProps = mActiveRenderTarget->getProperties();
1403
1404 bool clearEntireTarget = clearRect.width == 0 || clearRect.height == 0;
1405 clearEntireTarget |= (clearRect.x == 0 && clearRect.y == 0 && clearRect.width == rtProps.width && clearRect.height == rtProps.height);
1406
1407 if (!clearEntireTarget)
1408 {
1409 setScissorRect(clearRect.x, clearRect.y, clearRect.x + clearRect.width, clearRect.y + clearRect.height);
1410 setScissorTestEnable(true);
1411 }
1412
1413 if (buffers & FBT_COLOR)
1414 {
1415 // Enable buffer for writing if it isn't
1416 if (colorMask)
1417 {
1418 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1419 BS_CHECK_GL_ERROR();
1420 }
1421 }
1422 if (buffers & FBT_DEPTH)
1423 {
1424 // Enable buffer for writing if it isn't
1425 if (!mDepthWrite)
1426 {
1427 glDepthMask(GL_TRUE);
1428 BS_CHECK_GL_ERROR();
1429 }
1430 }
1431 if (buffers & FBT_STENCIL)
1432 {
1433 // Enable buffer for writing if it isn't
1434 glStencilMask(0xFFFFFFFF);
1435 BS_CHECK_GL_ERROR();
1436 }
1437
1438 if (targetMask == 0xFF)
1439 {
1440 GLbitfield flags = 0;
1441 if (buffers & FBT_COLOR)
1442 {
1443 flags |= GL_COLOR_BUFFER_BIT;
1444
1445 glClearColor(color.r, color.g, color.b, color.a);
1446 BS_CHECK_GL_ERROR();
1447 }
1448
1449 if (buffers & FBT_DEPTH)
1450 {
1451 flags |= GL_DEPTH_BUFFER_BIT;
1452
1453 glClearDepth(depth);
1454 BS_CHECK_GL_ERROR();
1455 }
1456
1457 if (buffers & FBT_STENCIL)
1458 {
1459 flags |= GL_STENCIL_BUFFER_BIT;
1460
1461 glClearStencil(stencil);
1462 BS_CHECK_GL_ERROR();
1463 }
1464
1465 // Clear buffers
1466 glClear(flags);
1467 BS_CHECK_GL_ERROR();
1468 }
1469 else
1470 {
1471 GLFrameBufferObject* fbo = nullptr;
1472 mActiveRenderTarget->getCustomAttribute("FBO", &fbo);
1473
1474 if (buffers & FBT_COLOR)
1475 {
1476 for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
1477 {
1478 if (fbo->hasColorBuffer(i) && ((1 << i) & targetMask) != 0)
1479 {
1480 glClearBufferfv(GL_COLOR, i, (GLfloat*)&color);
1481 BS_CHECK_GL_ERROR();
1482 }
1483 }
1484 }
1485
1486 if (buffers & FBT_DEPTH)
1487 {
1488 if (buffers & FBT_STENCIL)
1489 {
1490 glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
1491 BS_CHECK_GL_ERROR();
1492 }
1493 else
1494 {
1495 glClearBufferfv(GL_DEPTH, 0, &depth);
1496 BS_CHECK_GL_ERROR();
1497 }
1498 }
1499 else if (buffers & FBT_STENCIL)
1500 {
1501 INT32 stencilClear = (INT32)stencil;
1502 glClearBufferiv(GL_STENCIL, 0, &stencilClear);
1503 BS_CHECK_GL_ERROR();
1504 }
1505 }
1506
1507 if (!clearEntireTarget)
1508 {
1509 setScissorTestEnable(false);
1510 }
1511
1512 // Restore scissor test
1513 if (scissorTestEnabled)
1514 {
1515 glEnable(GL_SCISSOR_TEST);
1516 BS_CHECK_GL_ERROR();
1517
1518 mScissorTop = oldScissorTop;
1519 mScissorBottom = oldScissorBottom;
1520 mScissorLeft = oldScissorLeft;
1521 mScissorRight = oldScissorRight;
1522 }
1523
1524 // Reset buffer write state
1525 if (!mDepthWrite && (buffers & FBT_DEPTH))
1526 {
1527 glDepthMask(GL_FALSE);
1528 BS_CHECK_GL_ERROR();
1529 }
1530
1531 if (colorMask && (buffers & FBT_COLOR))
1532 {
1533 glColorMask(mColorWrite[0], mColorWrite[1], mColorWrite[2], mColorWrite[3]);
1534 BS_CHECK_GL_ERROR();
1535 }
1536
1537 if (buffers & FBT_STENCIL)
1538 {
1539 glStencilMask(mStencilWriteMask);
1540 BS_CHECK_GL_ERROR();
1541 }
1542
1543 BS_INC_RENDER_STAT(NumClears);
1544 }
1545
1546 /************************************************************************/
1547 /* PRIVATE */
1548 /************************************************************************/
1549
1550 void GLRenderAPI::setTextureAddressingMode(UINT16 unit, const UVWAddressingMode& uvw)
1551 {
1552 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_WRAP_S, getTextureAddressingMode(uvw.u));
1553 BS_CHECK_GL_ERROR();
1554
1555 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_WRAP_T, getTextureAddressingMode(uvw.v));
1556 BS_CHECK_GL_ERROR();
1557
1558 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_WRAP_R, getTextureAddressingMode(uvw.w));
1559 BS_CHECK_GL_ERROR();
1560 }
1561
1562 void GLRenderAPI::setTextureBorderColor(UINT16 unit, const Color& color)
1563 {
1564 GLfloat border[4] = { color.r, color.g, color.b, color.a };
1565 glTexParameterfv(mTextureInfos[unit].type, GL_TEXTURE_BORDER_COLOR, border);
1566 BS_CHECK_GL_ERROR();
1567 }
1568
1569 void GLRenderAPI::setTextureMipmapBias(UINT16 unit, float bias)
1570 {
1571 glTexParameterf(mTextureInfos[unit].type, GL_TEXTURE_LOD_BIAS, bias);
1572 BS_CHECK_GL_ERROR();
1573 }
1574
1575 void GLRenderAPI::setTextureMipmapRange(UINT16 unit, float min, float max)
1576 {
1577 glTexParameterf(mTextureInfos[unit].type, GL_TEXTURE_MIN_LOD, min);
1578 BS_CHECK_GL_ERROR();
1579
1580 glTexParameterf(mTextureInfos[unit].type, GL_TEXTURE_MAX_LOD, max);
1581 BS_CHECK_GL_ERROR();
1582 }
1583
1584 void GLRenderAPI::setSceneBlending(BlendFactor sourceFactor, BlendFactor destFactor, BlendOperation op)
1585 {
1586 GLint sourceBlend = getBlendMode(sourceFactor);
1587 GLint destBlend = getBlendMode(destFactor);
1588 if(sourceFactor == BF_ONE && destFactor == BF_ZERO)
1589 {
1590 glDisable(GL_BLEND);
1591 BS_CHECK_GL_ERROR();
1592 }
1593 else
1594 {
1595 glEnable(GL_BLEND);
1596 BS_CHECK_GL_ERROR();
1597
1598 glBlendFunc(sourceBlend, destBlend);
1599 BS_CHECK_GL_ERROR();
1600 }
1601
1602 GLint func = GL_FUNC_ADD;
1603 switch(op)
1604 {
1605 case BO_ADD:
1606 func = GL_FUNC_ADD;
1607 break;
1608 case BO_SUBTRACT:
1609 func = GL_FUNC_SUBTRACT;
1610 break;
1611 case BO_REVERSE_SUBTRACT:
1612 func = GL_FUNC_REVERSE_SUBTRACT;
1613 break;
1614 case BO_MIN:
1615 func = GL_MIN;
1616 break;
1617 case BO_MAX:
1618 func = GL_MAX;
1619 break;
1620 }
1621
1622 glBlendEquation(func);
1623 BS_CHECK_GL_ERROR();
1624 }
1625
1626 void GLRenderAPI::setSceneBlending(BlendFactor sourceFactor, BlendFactor destFactor,
1627 BlendFactor sourceFactorAlpha, BlendFactor destFactorAlpha, BlendOperation op, BlendOperation alphaOp)
1628 {
1629 GLint sourceBlend = getBlendMode(sourceFactor);
1630 GLint destBlend = getBlendMode(destFactor);
1631 GLint sourceBlendAlpha = getBlendMode(sourceFactorAlpha);
1632 GLint destBlendAlpha = getBlendMode(destFactorAlpha);
1633
1634 if(sourceFactor == BF_ONE && destFactor == BF_ZERO && sourceFactorAlpha == BF_ONE && destFactorAlpha == BF_ZERO)
1635 {
1636 glDisable(GL_BLEND);
1637 BS_CHECK_GL_ERROR();
1638 }
1639 else
1640 {
1641 glEnable(GL_BLEND);
1642 BS_CHECK_GL_ERROR();
1643
1644 glBlendFuncSeparate(sourceBlend, destBlend, sourceBlendAlpha, destBlendAlpha);
1645 BS_CHECK_GL_ERROR();
1646 }
1647
1648 GLint func = GL_FUNC_ADD, alphaFunc = GL_FUNC_ADD;
1649
1650 switch(op)
1651 {
1652 case BO_ADD:
1653 func = GL_FUNC_ADD;
1654 break;
1655 case BO_SUBTRACT:
1656 func = GL_FUNC_SUBTRACT;
1657 break;
1658 case BO_REVERSE_SUBTRACT:
1659 func = GL_FUNC_REVERSE_SUBTRACT;
1660 break;
1661 case BO_MIN:
1662 func = GL_MIN;
1663 break;
1664 case BO_MAX:
1665 func = GL_MAX;
1666 break;
1667 }
1668
1669 switch(alphaOp)
1670 {
1671 case BO_ADD:
1672 alphaFunc = GL_FUNC_ADD;
1673 break;
1674 case BO_SUBTRACT:
1675 alphaFunc = GL_FUNC_SUBTRACT;
1676 break;
1677 case BO_REVERSE_SUBTRACT:
1678 alphaFunc = GL_FUNC_REVERSE_SUBTRACT;
1679 break;
1680 case BO_MIN:
1681 alphaFunc = GL_MIN;
1682 break;
1683 case BO_MAX:
1684 alphaFunc = GL_MAX;
1685 break;
1686 }
1687
1688 glBlendEquationSeparate(func, alphaFunc);
1689 BS_CHECK_GL_ERROR();
1690 }
1691
1692 void GLRenderAPI::setAlphaToCoverage(bool enable)
1693 {
1694 static bool lasta2c = false;
1695
1696 if (enable != lasta2c)
1697 {
1698 if (enable)
1699 {
1700 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
1701 BS_CHECK_GL_ERROR();
1702 }
1703 else
1704 {
1705 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
1706 BS_CHECK_GL_ERROR();
1707 }
1708
1709 lasta2c = enable;
1710 }
1711 }
1712
1713 void GLRenderAPI::setScissorTestEnable(bool enable)
1714 {
1715 if (mActiveRenderTarget == nullptr)
1716 return;
1717
1718 const RenderTargetProperties& rtProps = mActiveRenderTarget->getProperties();
1719 GLsizei x, y, w, h;
1720 if (enable)
1721 {
1722 glEnable(GL_SCISSOR_TEST);
1723 BS_CHECK_GL_ERROR();
1724
1725 x = mScissorLeft;
1726 y = rtProps.height - mScissorBottom;
1727 w = mScissorRight - mScissorLeft;
1728 h = mScissorBottom - mScissorTop;
1729
1730 glScissor(x, y, w, h);
1731 BS_CHECK_GL_ERROR();
1732 }
1733 else
1734 {
1735 glDisable(GL_SCISSOR_TEST);
1736 BS_CHECK_GL_ERROR();
1737
1738 // GL requires you to reset the scissor when disabling
1739 x = mViewportLeft;
1740 y = rtProps.height - (mViewportTop + mViewportHeight);
1741 w = mViewportWidth;
1742 h = mViewportHeight;
1743
1744 glScissor(x, y, w, h);
1745 BS_CHECK_GL_ERROR();
1746 }
1747
1748 mScissorEnabled = enable;
1749 }
1750
1751 void GLRenderAPI::setMultisamplingEnable(bool enable)
1752 {
1753 if (enable)
1754 {
1755 glEnable(GL_MULTISAMPLE);
1756 BS_CHECK_GL_ERROR();
1757 }
1758 else
1759 {
1760 glDisable(GL_MULTISAMPLE);
1761 BS_CHECK_GL_ERROR();
1762 }
1763 }
1764
1765 void GLRenderAPI::setDepthClipEnable(bool enable)
1766 {
1767 if (!enable) // If clipping disabled, clamp is enabled
1768 {
1769 glEnable(GL_DEPTH_CLAMP);
1770 BS_CHECK_GL_ERROR();
1771 }
1772 else
1773 {
1774 glDisable(GL_DEPTH_CLAMP);
1775 BS_CHECK_GL_ERROR();
1776 }
1777 }
1778
1779 void GLRenderAPI::setAntialiasedLineEnable(bool enable)
1780 {
1781 if (enable)
1782 {
1783 glEnable(GL_LINE_SMOOTH);
1784 BS_CHECK_GL_ERROR();
1785 }
1786 else
1787 {
1788 glDisable(GL_LINE_SMOOTH);
1789 BS_CHECK_GL_ERROR();
1790 }
1791 }
1792
1793
1794 void GLRenderAPI::setCullingMode(CullingMode mode)
1795 {
1796 GLenum cullMode;
1797
1798 switch( mode )
1799 {
1800 case CULL_NONE:
1801 glDisable(GL_CULL_FACE);
1802 BS_CHECK_GL_ERROR();
1803 return;
1804 default:
1805 case CULL_CLOCKWISE:
1806 cullMode = GL_FRONT;
1807 break;
1808 case CULL_COUNTERCLOCKWISE:
1809 cullMode = GL_BACK;
1810 break;
1811 }
1812
1813 glEnable(GL_CULL_FACE);
1814 BS_CHECK_GL_ERROR();
1815
1816 glCullFace(cullMode);
1817 BS_CHECK_GL_ERROR();
1818 }
1819
1820 void GLRenderAPI::setDepthBufferCheckEnabled(bool enabled)
1821 {
1822 if (enabled)
1823 {
1824 glClearDepth(1.0f);
1825 BS_CHECK_GL_ERROR();
1826
1827 glEnable(GL_DEPTH_TEST);
1828 BS_CHECK_GL_ERROR();
1829 }
1830 else
1831 {
1832 glDisable(GL_DEPTH_TEST);
1833 BS_CHECK_GL_ERROR();
1834 }
1835 }
1836
1837 void GLRenderAPI::setDepthBufferWriteEnabled(bool enabled)
1838 {
1839 GLboolean flag = enabled ? GL_TRUE : GL_FALSE;
1840 glDepthMask(flag);
1841 BS_CHECK_GL_ERROR();
1842
1843 mDepthWrite = enabled;
1844 }
1845
1846 void GLRenderAPI::setDepthBufferFunction(CompareFunction func)
1847 {
1848 glDepthFunc(convertCompareFunction(func));
1849 BS_CHECK_GL_ERROR();
1850 }
1851
1852 void GLRenderAPI::setDepthBias(float constantBias, float slopeScaleBias)
1853 {
1854 if (constantBias != 0 || slopeScaleBias != 0)
1855 {
1856 glEnable(GL_POLYGON_OFFSET_FILL);
1857 BS_CHECK_GL_ERROR();
1858
1859 glEnable(GL_POLYGON_OFFSET_POINT);
1860 BS_CHECK_GL_ERROR();
1861
1862 glEnable(GL_POLYGON_OFFSET_LINE);
1863 BS_CHECK_GL_ERROR();
1864
1865 float scaledConstantBias = -constantBias * float((1 << 24) - 1); // Note: Assumes 24-bit depth buffer
1866 glPolygonOffset(slopeScaleBias, scaledConstantBias);
1867 BS_CHECK_GL_ERROR();
1868 }
1869 else
1870 {
1871 glDisable(GL_POLYGON_OFFSET_FILL);
1872 BS_CHECK_GL_ERROR();
1873
1874 glDisable(GL_POLYGON_OFFSET_POINT);
1875 BS_CHECK_GL_ERROR();
1876
1877 glDisable(GL_POLYGON_OFFSET_LINE);
1878 BS_CHECK_GL_ERROR();
1879 }
1880 }
1881
1882 void GLRenderAPI::setColorBufferWriteEnabled(bool red, bool green, bool blue, bool alpha)
1883 {
1884 glColorMask(red, green, blue, alpha);
1885 BS_CHECK_GL_ERROR();
1886
1887 mColorWrite[0] = red;
1888 mColorWrite[1] = blue;
1889 mColorWrite[2] = green;
1890 mColorWrite[3] = alpha;
1891 }
1892
1893 void GLRenderAPI::setPolygonMode(PolygonMode level)
1894 {
1895 GLenum glmode;
1896 switch(level)
1897 {
1898 case PM_WIREFRAME:
1899 glmode = GL_LINE;
1900 break;
1901 default:
1902 case PM_SOLID:
1903 glmode = GL_FILL;
1904 break;
1905 }
1906
1907 glPolygonMode(GL_FRONT_AND_BACK, glmode);
1908 BS_CHECK_GL_ERROR();
1909 }
1910
1911 void GLRenderAPI::setStencilCheckEnabled(bool enabled)
1912 {
1913 if (enabled)
1914 {
1915 glEnable(GL_STENCIL_TEST);
1916 BS_CHECK_GL_ERROR();
1917 }
1918 else
1919 {
1920 glDisable(GL_STENCIL_TEST);
1921 BS_CHECK_GL_ERROR();
1922 }
1923 }
1924
1925 void GLRenderAPI::setStencilBufferOperations(StencilOperation stencilFailOp,
1926 StencilOperation depthFailOp, StencilOperation passOp, bool front)
1927 {
1928 if (front)
1929 {
1930 glStencilOpSeparate(
1931 GL_FRONT,
1932 convertStencilOp(stencilFailOp),
1933 convertStencilOp(depthFailOp),
1934 convertStencilOp(passOp));
1935 BS_CHECK_GL_ERROR();
1936 }
1937 else
1938 {
1939 glStencilOpSeparate(
1940 GL_BACK,
1941 convertStencilOp(stencilFailOp),
1942 convertStencilOp(depthFailOp),
1943 convertStencilOp(passOp));
1944 BS_CHECK_GL_ERROR();
1945 }
1946 }
1947
1948 void GLRenderAPI::setStencilBufferFunc(CompareFunction func, UINT32 mask, bool front)
1949 {
1950 mStencilReadMask = mask;
1951
1952 if(front)
1953 {
1954 mStencilCompareFront = func;
1955 glStencilFuncSeparate(GL_FRONT, convertCompareFunction(mStencilCompareFront), mStencilRefValue, mStencilReadMask);
1956 BS_CHECK_GL_ERROR();
1957 }
1958 else
1959 {
1960 mStencilCompareBack = func;
1961 glStencilFuncSeparate(GL_BACK, convertCompareFunction(mStencilCompareBack), mStencilRefValue, mStencilReadMask);
1962 BS_CHECK_GL_ERROR();
1963 }
1964 }
1965
1966 void GLRenderAPI::setStencilBufferWriteMask(UINT32 mask)
1967 {
1968 mStencilWriteMask = mask;
1969
1970 glStencilMask(mask);
1971 BS_CHECK_GL_ERROR();
1972 }
1973
1974 void GLRenderAPI::setStencilRefValue(UINT32 refValue)
1975 {
1976 THROW_IF_NOT_CORE_THREAD;
1977
1978 mStencilRefValue = refValue;
1979
1980 glStencilFuncSeparate(GL_FRONT, convertCompareFunction(mStencilCompareFront), mStencilRefValue, mStencilReadMask);
1981 BS_CHECK_GL_ERROR();
1982
1983 glStencilFuncSeparate(GL_BACK, convertCompareFunction(mStencilCompareBack), mStencilRefValue, mStencilReadMask);
1984 BS_CHECK_GL_ERROR();
1985 }
1986
1987 void GLRenderAPI::setTextureFiltering(UINT16 unit, FilterType ftype, FilterOptions fo)
1988 {
1989 switch(ftype)
1990 {
1991 case FT_MIN:
1992 mMinFilter = fo;
1993 // Combine with existing mip filter
1994 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_MIN_FILTER, getCombinedMinMipFilter());
1995 BS_CHECK_GL_ERROR();
1996 break;
1997 case FT_MAG:
1998 switch (fo)
1999 {
2000 case FO_ANISOTROPIC: // GL treats linear and aniso the same
2001 case FO_LINEAR:
2002 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2003 BS_CHECK_GL_ERROR();
2004 break;
2005 case FO_POINT:
2006 case FO_NONE:
2007 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2008 BS_CHECK_GL_ERROR();
2009 break;
2010 default:
2011 break;
2012 }
2013 break;
2014 case FT_MIP:
2015 mMipFilter = fo;
2016 // Combine with existing min filter
2017 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_MIN_FILTER, getCombinedMinMipFilter());
2018 BS_CHECK_GL_ERROR();
2019 break;
2020 }
2021 }
2022
2023 void GLRenderAPI::setTextureAnisotropy(UINT16 unit, UINT32 maxAnisotropy)
2024 {
2025 GLfloat maxSupportAnisotropy = 0;
2026 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxSupportAnisotropy);
2027 BS_CHECK_GL_ERROR();
2028
2029 if (maxAnisotropy > maxSupportAnisotropy)
2030 maxAnisotropy = maxSupportAnisotropy ? static_cast<UINT32>(maxSupportAnisotropy) : 1;
2031
2032 if(maxAnisotropy < 1)
2033 maxAnisotropy = 1;
2034
2035 glTexParameterf(mTextureInfos[unit].type, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)maxAnisotropy);
2036 BS_CHECK_GL_ERROR();
2037 }
2038
2039 void GLRenderAPI::setTextureCompareMode(UINT16 unit, CompareFunction compare)
2040 {
2041 if (compare == CMPF_ALWAYS_PASS)
2042 {
2043 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_COMPARE_MODE, GL_NONE);
2044 BS_CHECK_GL_ERROR();
2045 }
2046 else
2047 {
2048 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
2049 BS_CHECK_GL_ERROR();
2050
2051 glTexParameteri(mTextureInfos[unit].type, GL_TEXTURE_COMPARE_FUNC, convertCompareFunction(compare));
2052 BS_CHECK_GL_ERROR();
2053 }
2054 }
2055
2056 bool GLRenderAPI::activateGLTextureUnit(UINT16 unit)
2057 {
2058 if (mActiveTextureUnit != unit)
2059 {
2060 if (unit < getCapabilities(0).numCombinedTextureUnits)
2061 {
2062 glActiveTexture(GL_TEXTURE0 + unit);
2063 BS_CHECK_GL_ERROR();
2064
2065 mActiveTextureUnit = unit;
2066 return true;
2067 }
2068 else if (!unit)
2069 {
2070 // Always ok to use the first unit
2071 return true;
2072 }
2073 else
2074 {
2075 LOGWRN("Provided texture unit index is higher than OpenGL supports. Provided: " + toString(unit) +
2076 ". Supported range: 0 .. " + toString(getCapabilities(0).numCombinedTextureUnits - 1));
2077 return false;
2078 }
2079 }
2080 else
2081 {
2082 return true;
2083 }
2084 }
2085
2086 void GLRenderAPI::beginDraw()
2087 {
2088 if(mDrawCallInProgress)
2089 BS_EXCEPT(InternalErrorException, "Calling beginDraw without finishing previous draw call. Please call endDraw().");
2090
2091 mDrawCallInProgress = true;
2092
2093 if(mCurrentVertexProgram == nullptr)
2094 {
2095 LOGWRN("Cannot render without a set vertex shader.");
2096 return;
2097 }
2098
2099 if(mBoundVertexDeclaration == nullptr)
2100 {
2101 LOGWRN("Cannot render without a set vertex declaration.");
2102 return;
2103 }
2104
2105 const GLSLProgramPipeline* pipeline = mProgramPipelineManager->getPipeline(mCurrentVertexProgram.get(),
2106 mCurrentFragmentProgram.get(), mCurrentGeometryProgram.get(), mCurrentHullProgram.get(), mCurrentDomainProgram.get());
2107
2108 glUseProgram(0);
2109 BS_CHECK_GL_ERROR();
2110
2111 if(mActivePipeline != pipeline)
2112 {
2113 glBindProgramPipeline(pipeline->glHandle);
2114 BS_CHECK_GL_ERROR();
2115
2116 mActivePipeline = pipeline;
2117 }
2118
2119 const GLVertexArrayObject& vao = GLVertexArrayObjectManager::instance().getVAO(
2120 mCurrentVertexProgram,
2121 mBoundVertexDeclaration,
2122 mBoundVertexBuffers);
2123
2124 glBindVertexArray(vao.getGLHandle());
2125 BS_CHECK_GL_ERROR();
2126
2127 BS_INC_RENDER_STAT(NumVertexBufferBinds);
2128 }
2129
2130 void GLRenderAPI::endDraw()
2131 {
2132 if(!mDrawCallInProgress)
2133 return;
2134
2135#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
2136 glMemoryBarrier(GL_ALL_BARRIER_BITS);
2137#endif
2138
2139 mDrawCallInProgress = false;
2140 }
2141
2142 GLfloat GLRenderAPI::getCurrentAnisotropy(UINT16 unit)
2143 {
2144 GLfloat curAniso = 0;
2145 glGetTexParameterfv(mTextureInfos[unit].type, GL_TEXTURE_MAX_ANISOTROPY_EXT, &curAniso);
2146 BS_CHECK_GL_ERROR();
2147
2148 return curAniso ? curAniso : 1;
2149 }
2150
2151 GLint GLRenderAPI::convertStencilOp(StencilOperation op) const
2152 {
2153 switch (op)
2154 {
2155 case SOP_KEEP:
2156 return GL_KEEP;
2157 case SOP_ZERO:
2158 return GL_ZERO;
2159 case SOP_REPLACE:
2160 return GL_REPLACE;
2161 case SOP_INCREMENT:
2162 return GL_INCR;
2163 case SOP_DECREMENT:
2164 return GL_DECR;
2165 case SOP_INCREMENT_WRAP:
2166 return GL_INCR_WRAP;
2167 case SOP_DECREMENT_WRAP:
2168 return GL_DECR_WRAP;
2169 case SOP_INVERT:
2170 return GL_INVERT;
2171 }
2172
2173 return SOP_KEEP;
2174 }
2175
2176 GLint GLRenderAPI::convertCompareFunction(CompareFunction func) const
2177 {
2178 switch (func)
2179 {
2180 case CMPF_ALWAYS_FAIL:
2181 return GL_NEVER;
2182 case CMPF_ALWAYS_PASS:
2183 return GL_ALWAYS;
2184 case CMPF_LESS:
2185 return GL_LESS;
2186 case CMPF_LESS_EQUAL:
2187 return GL_LEQUAL;
2188 case CMPF_EQUAL:
2189 return GL_EQUAL;
2190 case CMPF_NOT_EQUAL:
2191 return GL_NOTEQUAL;
2192 case CMPF_GREATER_EQUAL:
2193 return GL_GEQUAL;
2194 case CMPF_GREATER:
2195 return GL_GREATER;
2196 }
2197
2198 return GL_ALWAYS;
2199 }
2200
2201 GLuint GLRenderAPI::getCombinedMinMipFilter() const
2202 {
2203 switch (mMinFilter)
2204 {
2205 case FO_ANISOTROPIC:
2206 case FO_LINEAR:
2207 switch (mMipFilter)
2208 {
2209 case FO_ANISOTROPIC:
2210 case FO_LINEAR:
2211 // Linear min, linear mip
2212 return GL_LINEAR_MIPMAP_LINEAR;
2213 case FO_POINT:
2214 // Linear min, point mip
2215 return GL_LINEAR_MIPMAP_NEAREST;
2216 case FO_NONE:
2217 // Linear min, no mip
2218 return GL_LINEAR;
2219 default:
2220 break;
2221 }
2222 break;
2223 case FO_POINT:
2224 case FO_NONE:
2225 switch (mMipFilter)
2226 {
2227 case FO_ANISOTROPIC:
2228 case FO_LINEAR:
2229 // Nearest min, linear mip
2230 return GL_NEAREST_MIPMAP_LINEAR;
2231 case FO_POINT:
2232 // Nearest min, point mip
2233 return GL_NEAREST_MIPMAP_NEAREST;
2234 case FO_NONE:
2235 // Nearest min, no mip
2236 return GL_NEAREST;
2237 default:
2238 break;
2239 }
2240 break;
2241 default:
2242 break;
2243 }
2244
2245 // Should never get here
2246 return 0;
2247 }
2248
2249 GLint GLRenderAPI::getBlendMode(BlendFactor blendMode) const
2250 {
2251 switch (blendMode)
2252 {
2253 case BF_ONE:
2254 return GL_ONE;
2255 case BF_ZERO:
2256 return GL_ZERO;
2257 case BF_DEST_COLOR:
2258 return GL_DST_COLOR;
2259 case BF_SOURCE_COLOR:
2260 return GL_SRC_COLOR;
2261 case BF_INV_DEST_COLOR:
2262 return GL_ONE_MINUS_DST_COLOR;
2263 case BF_INV_SOURCE_COLOR:
2264 return GL_ONE_MINUS_SRC_COLOR;
2265 case BF_DEST_ALPHA:
2266 return GL_DST_ALPHA;
2267 case BF_SOURCE_ALPHA:
2268 return GL_SRC_ALPHA;
2269 case BF_INV_DEST_ALPHA:
2270 return GL_ONE_MINUS_DST_ALPHA;
2271 case BF_INV_SOURCE_ALPHA:
2272 return GL_ONE_MINUS_SRC_ALPHA;
2273 }
2274
2275 return GL_ONE;
2276 }
2277
2278 GLint GLRenderAPI::getTextureAddressingMode(TextureAddressingMode tam) const
2279 {
2280 switch (tam)
2281 {
2282 default:
2283 case TAM_WRAP:
2284 return GL_REPEAT;
2285 case TAM_MIRROR:
2286 return GL_MIRRORED_REPEAT;
2287 case TAM_CLAMP:
2288 return GL_CLAMP_TO_EDGE;
2289 case TAM_BORDER:
2290 return GL_CLAMP_TO_BORDER;
2291 }
2292 }
2293
2294 GLint GLRenderAPI::getGLDrawMode() const
2295 {
2296 GLint primType;
2297
2298 // Use adjacency if there is a geometry program and it requested adjacency info
2299 bool useAdjacency = (mCurrentGeometryProgram != nullptr && mCurrentGeometryProgram->isAdjacencyInfoRequired());
2300 switch (mCurrentDrawOperation)
2301 {
2302 case DOT_POINT_LIST:
2303 primType = GL_POINTS;
2304 break;
2305 case DOT_LINE_LIST:
2306 primType = useAdjacency ? GL_LINES_ADJACENCY : GL_LINES;
2307 break;
2308 case DOT_LINE_STRIP:
2309 primType = useAdjacency ? GL_LINE_STRIP_ADJACENCY : GL_LINE_STRIP;
2310 break;
2311 default:
2312 case DOT_TRIANGLE_LIST:
2313 primType = useAdjacency ? GL_TRIANGLES_ADJACENCY : GL_TRIANGLES;
2314 break;
2315 case DOT_TRIANGLE_STRIP:
2316 primType = useAdjacency ? GL_TRIANGLE_STRIP_ADJACENCY : GL_TRIANGLE_STRIP;
2317 break;
2318 case DOT_TRIANGLE_FAN:
2319 primType = GL_TRIANGLE_FAN;
2320 break;
2321 }
2322
2323 return primType;
2324 }
2325
2326 SPtr<GLSLGpuProgram> GLRenderAPI::getActiveProgram(GpuProgramType gptype) const
2327 {
2328 switch (gptype)
2329 {
2330 case GPT_VERTEX_PROGRAM:
2331 return mCurrentVertexProgram;
2332 case GPT_FRAGMENT_PROGRAM:
2333 return mCurrentFragmentProgram;
2334 case GPT_GEOMETRY_PROGRAM:
2335 return mCurrentGeometryProgram;
2336 case GPT_DOMAIN_PROGRAM:
2337 return mCurrentDomainProgram;
2338 case GPT_HULL_PROGRAM:
2339 return mCurrentHullProgram;
2340 case GPT_COMPUTE_PROGRAM:
2341 return mCurrentComputeProgram;
2342 default:
2343 BS_EXCEPT(InvalidParametersException, "Unsupported gpu program type: " + toString(gptype));
2344 }
2345
2346 return nullptr;
2347 }
2348
2349 void GLRenderAPI::initFromCaps(RenderAPICapabilities* caps)
2350 {
2351 if(caps->renderAPIName != getName())
2352 {
2353 BS_EXCEPT(InvalidParametersException,
2354 "Trying to initialize GLRenderAPI from RenderSystemCapabilities that do not support OpenGL");
2355 }
2356
2357#if BS_DEBUG_MODE && (BS_OPENGL_4_3 || BS_OPENGLES_3_2)
2358 if (mGLSupport->checkExtension("GL_ARB_debug_output"))
2359 {
2360 glDebugMessageCallback(&openGlErrorCallback, 0);
2361 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
2362 }
2363#endif
2364
2365 bs::HardwareBufferManager::startUp();
2366 HardwareBufferManager::startUp<GLHardwareBufferManager>();
2367
2368 // GPU Program Manager setup
2369 mGLSLProgramFactory = bs_new<GLSLProgramFactory>();
2370 if(caps->isShaderProfileSupported("glsl")) // Check for most recent GLSL support
2371 GpuProgramManager::instance().addFactory("glsl", mGLSLProgramFactory);
2372
2373 if(caps->isShaderProfileSupported("glsl4_1")) // Check for OpenGL 4.1 compatible version
2374 GpuProgramManager::instance().addFactory("glsl4_1", mGLSLProgramFactory);
2375
2376 GLRTTManager::startUp<GLRTTManager>();
2377
2378 mNumTextureUnits = caps->numCombinedTextureUnits;
2379 mTextureInfos = bs_newN<TextureInfo>(mNumTextureUnits);
2380
2381 bs::TextureManager::startUp<bs::GLTextureManager>(std::ref(*mGLSupport));
2382 TextureManager::startUp<GLTextureManager>(std::ref(*mGLSupport));
2383 }
2384
2385 void GLRenderAPI::switchContext(const SPtr<GLContext>& context, const RenderWindow& window)
2386 {
2387 // Unbind pipeline and rebind to new context later
2388 setGraphicsPipeline(nullptr);
2389
2390 if (mCurrentContext)
2391 mCurrentContext->endCurrent();
2392
2393 mCurrentContext = context;
2394 mCurrentContext->setCurrent(window);
2395
2396 // Must reset depth/colour write mask to according with user desired, otherwise, clearFrameBuffer would be wrong
2397 // because the value we recorded may be different from the real state stored in GL context.
2398 glDepthMask(mDepthWrite);
2399 BS_CHECK_GL_ERROR();
2400
2401 glColorMask(mColorWrite[0], mColorWrite[1], mColorWrite[2], mColorWrite[3]);
2402 BS_CHECK_GL_ERROR();
2403
2404 glStencilMask(mStencilWriteMask);
2405 BS_CHECK_GL_ERROR();
2406 }
2407
2408 void GLRenderAPI::initCapabilities(RenderAPICapabilities& caps) const
2409 {
2410 Vector<String> tokens = StringUtil::split(mGLSupport->getGLVersion(), ".");
2411
2412 DriverVersion driverVersion;
2413 if (!tokens.empty())
2414 {
2415 driverVersion.major = parseINT32(tokens[0]);
2416 if (tokens.size() > 1)
2417 driverVersion.minor = parseINT32(tokens[1]);
2418 if (tokens.size() > 2)
2419 driverVersion.release = parseINT32(tokens[2]);
2420 }
2421 driverVersion.build = 0;
2422
2423 caps.driverVersion = driverVersion;
2424 caps.renderAPIName = getName();
2425
2426 const char* deviceName = (const char*)glGetString(GL_RENDERER);
2427 caps.deviceName = deviceName;
2428
2429 const char* vendorName = (const char*)glGetString(GL_VENDOR);
2430 if (strstr(vendorName, "NVIDIA"))
2431 caps.deviceVendor = GPU_NVIDIA;
2432 else if (strstr(vendorName, "ATI"))
2433 caps.deviceVendor = GPU_AMD;
2434 else if (strstr(vendorName, "AMD"))
2435 caps.deviceVendor = GPU_AMD;
2436 else if (strstr(vendorName, "Intel"))
2437 caps.deviceVendor = GPU_INTEL;
2438 else
2439 caps.deviceVendor = GPU_UNKNOWN;
2440
2441#if BS_OPENGL_4_1
2442 caps.addShaderProfile("glsl4_1");
2443#endif
2444
2445#if BS_OPENGL_4_5
2446 caps.addShaderProfile("glsl");
2447#endif
2448
2449 caps.setCapability(RSC_TEXTURE_COMPRESSION_BC);
2450
2451#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2452 caps.setCapability(RSC_GEOMETRY_PROGRAM);
2453#endif
2454
2455#if BS_OPENGL_4_2 || BS_OPENGLES_3_2
2456 caps.setCapability(RSC_LOAD_STORE);
2457 caps.setCapability(RSC_LOAD_STORE_MSAA);
2458#endif
2459
2460#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
2461 caps.setCapability(RSC_TEXTURE_VIEWS);
2462#endif
2463
2464#if BS_PLATFORM != BS_PLATFORM_OSX
2465 caps.setCapability(RSC_RENDER_TARGET_LAYERS);
2466#endif
2467
2468 caps.conventions.uvYAxis = Conventions::Axis::Up;
2469 caps.conventions.matrixOrder = Conventions::MatrixOrder::ColumnMajor;
2470 caps.minDepth = -1.0f;
2471 caps.maxDepth = 1.0f;
2472
2473 GLint maxOutputVertices;
2474
2475#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2476 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxOutputVertices);
2477 BS_CHECK_GL_ERROR();
2478#else
2479 maxOutputVertices = 0;
2480#endif
2481
2482 caps.geometryProgramNumOutputVertices = maxOutputVertices;
2483
2484 // Max number of fragment shader textures
2485 GLint units;
2486 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &units);
2487 BS_CHECK_GL_ERROR();
2488
2489 caps.numTextureUnitsPerStage[GPT_FRAGMENT_PROGRAM] = static_cast<UINT16>(units);
2490
2491 // Max number of vertex shader textures
2492 GLint vUnits;
2493 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &vUnits);
2494 BS_CHECK_GL_ERROR();
2495
2496 caps.numTextureUnitsPerStage[GPT_VERTEX_PROGRAM] = static_cast<UINT16>(vUnits);
2497
2498 GLint numUniformBlocks;
2499 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &numUniformBlocks);
2500 BS_CHECK_GL_ERROR();
2501
2502 caps.numGpuParamBlockBuffersPerStage[GPT_VERTEX_PROGRAM] = numUniformBlocks;
2503
2504 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &numUniformBlocks);
2505 BS_CHECK_GL_ERROR();
2506
2507 caps.numGpuParamBlockBuffersPerStage[GPT_FRAGMENT_PROGRAM] = numUniformBlocks;
2508
2509 {
2510 GLint geomUnits;
2511
2512#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2513 glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &geomUnits);
2514 BS_CHECK_GL_ERROR();
2515#else
2516 geomUnits = 0;
2517#endif
2518
2519 caps.numTextureUnitsPerStage[GPT_GEOMETRY_PROGRAM] = static_cast<UINT16>(geomUnits);
2520
2521#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2522 glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &numUniformBlocks);
2523 BS_CHECK_GL_ERROR();
2524#else
2525 numUniformBlocks = 0;
2526#endif
2527
2528 caps.numGpuParamBlockBuffersPerStage[GPT_GEOMETRY_PROGRAM] = numUniformBlocks;
2529 }
2530
2531 if (mGLSupport->checkExtension("GL_ARB_tessellation_shader"))
2532 {
2533#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2534 caps.setCapability(RSC_TESSELLATION_PROGRAM);
2535#endif
2536
2537#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2538 glGetIntegerv(GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, &numUniformBlocks);
2539 BS_CHECK_GL_ERROR();
2540#else
2541 numUniformBlocks = 0;
2542#endif
2543
2544 caps.numGpuParamBlockBuffersPerStage[GPT_HULL_PROGRAM] = numUniformBlocks;
2545
2546#if BS_OPENGL_4_1 || BS_OPENGLES_3_2
2547 glGetIntegerv(GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, &numUniformBlocks);
2548 BS_CHECK_GL_ERROR();
2549#else
2550 numUniformBlocks = 0;
2551#endif
2552
2553 caps.numGpuParamBlockBuffersPerStage[GPT_DOMAIN_PROGRAM] = numUniformBlocks;
2554 }
2555
2556 if (mGLSupport->checkExtension("GL_ARB_compute_shader"))
2557 {
2558#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
2559 caps.setCapability(RSC_COMPUTE_PROGRAM);
2560#endif
2561
2562 GLint computeUnits;
2563
2564#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
2565 glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &computeUnits);
2566 BS_CHECK_GL_ERROR();
2567#else
2568 computeUnits = 0;
2569#endif
2570
2571 caps.numTextureUnitsPerStage[GPT_COMPUTE_PROGRAM] = static_cast<UINT16>(computeUnits);
2572
2573#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
2574 glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &numUniformBlocks);
2575 BS_CHECK_GL_ERROR();
2576#else
2577 numUniformBlocks = 0;
2578#endif
2579
2580 caps.numGpuParamBlockBuffersPerStage[GPT_COMPUTE_PROGRAM] = numUniformBlocks;
2581
2582 // Max number of load-store textures
2583 GLint lsfUnits;
2584
2585#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
2586 glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &lsfUnits);
2587 BS_CHECK_GL_ERROR();
2588#else
2589 lsfUnits = 0;
2590#endif
2591
2592 caps.numLoadStoreTextureUnitsPerStage[GPT_FRAGMENT_PROGRAM] = static_cast<UINT16>(lsfUnits);
2593
2594 GLint lscUnits;
2595
2596#if BS_OPENGL_4_3 || BS_OPENGLES_3_1
2597 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &lscUnits);
2598 BS_CHECK_GL_ERROR();
2599#else
2600 lscUnits = 0;
2601#endif
2602
2603 caps.numLoadStoreTextureUnitsPerStage[GPT_COMPUTE_PROGRAM] = static_cast<UINT16>(lscUnits);
2604
2605 GLint combinedLoadStoreTextureUnits;
2606
2607#if BS_OPENGL_4_2 || BS_OPENGLES_3_1
2608 glGetIntegerv(GL_MAX_IMAGE_UNITS, &combinedLoadStoreTextureUnits);
2609 BS_CHECK_GL_ERROR();
2610#else
2611 combinedLoadStoreTextureUnits = 0;
2612#endif
2613
2614 caps.numCombinedLoadStoreTextureUnits = static_cast<UINT16>(combinedLoadStoreTextureUnits);
2615 }
2616
2617 GLint combinedTexUnits;
2618 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &combinedTexUnits);
2619 BS_CHECK_GL_ERROR();
2620
2621 caps.numCombinedTextureUnits = static_cast<UINT16>(combinedTexUnits);
2622
2623 GLint combinedUniformBlockUnits;
2624 glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &combinedUniformBlockUnits);
2625 BS_CHECK_GL_ERROR();
2626
2627 caps.numCombinedParamBlockBuffers = static_cast<UINT16>(combinedUniformBlockUnits);
2628 caps.numMultiRenderTargets = 8;
2629 }
2630
2631 void GLRenderAPI::makeGLMatrix(GLfloat gl_matrix[16], const Matrix4& m)
2632 {
2633 UINT32 x = 0;
2634 for (UINT32 i = 0; i < 4; i++)
2635 {
2636 for (UINT32 j = 0; j < 4; j++)
2637 {
2638 gl_matrix[x] = m[j][i];
2639 x++;
2640 }
2641 }
2642 }
2643
2644 void GLRenderAPI::applyViewport()
2645 {
2646 if (mActiveRenderTarget == nullptr)
2647 return;
2648
2649 const RenderTargetProperties& rtProps = mActiveRenderTarget->getProperties();
2650
2651 // Calculate the "lower-left" corner of the viewport
2652 mViewportLeft = (UINT32)(rtProps.width * mViewportNorm.x);
2653 mViewportTop = (UINT32)(rtProps.height * mViewportNorm.y);
2654 mViewportWidth = (UINT32)(rtProps.width * mViewportNorm.width);
2655 mViewportHeight = (UINT32)(rtProps.height * mViewportNorm.height);
2656
2657 glViewport(mViewportLeft, mViewportTop, mViewportWidth, mViewportHeight);
2658 BS_CHECK_GL_ERROR();
2659
2660 // Configure the viewport clipping
2661 if (!mScissorEnabled)
2662 {
2663 glEnable(GL_SCISSOR_TEST);
2664 BS_CHECK_GL_ERROR();
2665
2666 glScissor(mViewportLeft, mViewportTop, mViewportWidth, mViewportHeight);
2667 BS_CHECK_GL_ERROR();
2668 }
2669 }
2670
2671 /************************************************************************/
2672 /* UTILITY */
2673 /************************************************************************/
2674
2675 void GLRenderAPI::convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest)
2676 {
2677 dest = matrix;
2678 }
2679
2680 GpuParamBlockDesc GLRenderAPI::generateParamBlockDesc(const String& name, Vector<GpuParamDataDesc>& params)
2681 {
2682 GpuParamBlockDesc block;
2683 block.blockSize = 0;
2684 block.isShareable = true;
2685 block.name = name;
2686 block.slot = 0;
2687 block.set = 0;
2688
2689 for (auto& param : params)
2690 {
2691 UINT32 size;
2692
2693 if(param.type == GPDT_STRUCT)
2694 {
2695 // Structs are always aligned and rounded up to vec4
2696 size = Math::divideAndRoundUp(param.elementSize, 16U) * 4;
2697 block.blockSize = Math::divideAndRoundUp(block.blockSize, 4U) * 4;
2698 }
2699 else
2700 size = GLSLParamParser::calcInterfaceBlockElementSizeAndOffset(param.type, param.arraySize, block.blockSize);
2701
2702 if (param.arraySize > 1)
2703 {
2704 param.elementSize = size;
2705 param.arrayElementStride = size;
2706 param.cpuMemOffset = block.blockSize;
2707 param.gpuMemOffset = 0;
2708
2709 block.blockSize += size * param.arraySize;
2710 }
2711 else
2712 {
2713 param.elementSize = size;
2714 param.arrayElementStride = size;
2715 param.cpuMemOffset = block.blockSize;
2716 param.gpuMemOffset = 0;
2717
2718 block.blockSize += size;
2719 }
2720
2721 param.paramBlockSlot = 0;
2722 param.paramBlockSet = 0;
2723 }
2724
2725 // Constant buffer size must always be a multiple of 16
2726 if (block.blockSize % 4 != 0)
2727 block.blockSize += (4 - (block.blockSize % 4));
2728
2729 return block;
2730 }
2731
2732#if BS_OPENGL_4_3 || BS_OPENGLES_3_2
2733 void openGlErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
2734 const GLchar *message, GLvoid *userParam)
2735 {
2736 if (type != GL_DEBUG_TYPE_PERFORMANCE && type != GL_DEBUG_TYPE_OTHER)
2737 {
2738 BS_EXCEPT(RenderingAPIException, "OpenGL error: " + String(message));
2739 }
2740 }
2741#endif
2742}}
2743