| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174 |
- /****************************************************************************
- Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
- http://www.cocos2d-x.org
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #include "DeviceGraphics.h"
- #include "VertexBuffer.h"
- #include "IndexBuffer.h"
- #include "FrameBuffer.h"
- #include "GraphicsHandle.h"
- #include "Texture2D.h"
- #include "RenderTarget.h"
- #include "Program.h"
- #include "GFXUtils.h"
- #include "platform/CCPlatformConfig.h"
- #include "base/CCGLUtils.h"
- RENDERER_BEGIN
- static_assert(sizeof(int) == sizeof(GLint), "ERROR: GLint isn't equal to int!");
- static_assert(sizeof(float) == sizeof(GLfloat), "ERROR: GLfloat isn't equal to float!");
- namespace
- {
- void attach(GLenum location, const RenderTarget* target)
- {
- if (nullptr != dynamic_cast<const Texture2D*>(target))
- {
- GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, location, GL_TEXTURE_2D, target->getHandle(), 0));
- }
- else
- {
- GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, location, GL_RENDERBUFFER, target->getHandle()));
- }
- }
- } // namespace {
- DeviceGraphics* DeviceGraphics::getInstance()
- {
- static DeviceGraphics* __instance = nullptr;
- if (__instance == nullptr)
- __instance = new (std::nothrow) DeviceGraphics();
- return __instance;
- }
- void DeviceGraphics::setFrameBuffer(const FrameBuffer* fb)
- {
- if (fb == _frameBuffer)
- return;
-
- // should reset view port rect when switch frame buffer
- _vx = _vy = _vw = _vh = 0;
-
- RENDERER_SAFE_RELEASE(_frameBuffer);
- _frameBuffer = const_cast<FrameBuffer*>(fb);
- RENDERER_SAFE_RETAIN(_frameBuffer);
-
- if (nullptr == fb)
- {
- GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, _defaultFbo));
- return;
- }
-
- GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fb->getHandle()));
-
- int i = 0;
- const auto& colorBuffers = fb->getColorBuffers();
- for (const auto& colorBuffer : colorBuffers)
- attach(GL_COLOR_ATTACHMENT0 + i, colorBuffer);
- for (i = static_cast<int>(colorBuffers.size()); i < _caps.maxColorAttatchments; ++i)
- {
- GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0));
- }
- if (0 == colorBuffers.size())
- {
- // If not draw buffer is needed, should invoke this line explicitly, or it will cause
- // GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER and GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER error.
- // https://stackoverflow.com/questions/28313782/porting-opengl-es-framebuffer-to-opengl
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- #endif
- }
-
- if (_frameBuffer->getDepthBuffer())
- attach(GL_DEPTH_ATTACHMENT, _frameBuffer->getDepthBuffer());
-
- if (_frameBuffer->getStencilBuffer())
- attach(GL_STENCIL_ATTACHMENT, _frameBuffer->getStencilBuffer());
-
- // if (_frameBuffer->getDepthStencilBuffer())
- // attach(GL_DEPTH_STENCIL_ATTACHMENT, _frameBuffer->getDepthStencilBuffer());
-
- auto result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- if (GL_FRAMEBUFFER_COMPLETE != result)
- RENDERER_LOGE("Framebuffer status error: 0x%x", result);
- }
- void DeviceGraphics::setViewport(int x, int y, int w, int h)
- {
- if (_vx != x ||
- _vy != y ||
- _vw != w ||
- _vh != h)
- {
- _vx = x;
- _vy = y;
- _vw = w;
- _vh = h;
- GL_CHECK(ccViewport(_vx, _vy, _vw, _vh));
- }
- }
- void DeviceGraphics::setScissor(int x, int y, int w, int h)
- {
- if (_sx != x ||
- _sy != y ||
- _sw != w ||
- _sh != h)
- {
- _sx = x;
- _sy = y;
- _sw = w;
- _sh = h;
- ccScissor(_sx, _sy, _sw, _sh);
- }
- }
- void DeviceGraphics::clear(uint8_t flags, Color4F *color, double depth, int32_t stencil)
- {
- GLbitfield mask = 0;
- if (flags & ClearFlag::COLOR)
- {
- mask |= GL_COLOR_BUFFER_BIT;
- GL_CHECK(glClearColor(color->r, color->g, color->b, color->a));
- }
-
- if (flags & ClearFlag::DEPTH)
- {
- mask |= GL_DEPTH_BUFFER_BIT;
- GL_CHECK(glClearDepth(depth));
-
- GL_CHECK(glEnable(GL_DEPTH_TEST));
- GL_CHECK(glDepthMask(GL_TRUE));
- GL_CHECK(glDepthFunc(GL_ALWAYS));
- }
-
- if (flags & ClearFlag::STENCIL)
- {
- mask |= GL_STENCIL_BUFFER_BIT;
- GL_CHECK(glClearStencil(stencil));
- }
-
- GL_CHECK(glClear(mask));
-
- // Restore depth related state.
- if (flags & ClearFlag::DEPTH)
- {
- if (!_currentState->depthTest)
- {
- GL_CHECK(glDisable(GL_DEPTH_TEST));
- }
- else
- {
- if (!_currentState->depthWrite)
- {
- GL_CHECK(glDepthMask(GL_FALSE));
- }
- if (_currentState->depthFunc != DepthFunc::ALWAYS)
- {
- GL_CHECK(glDepthFunc(static_cast<GLenum>(_currentState->depthFunc)));
- }
- }
- }
- }
- void DeviceGraphics::enableBlend()
- {
- _nextState->blend = true;
- }
- void DeviceGraphics::enableDepthTest()
- {
- _nextState->depthTest = true;
- }
- void DeviceGraphics::enableDepthWrite()
- {
- _nextState->depthWrite = true;
- }
- void DeviceGraphics::enableStencilTest()
- {
- _nextState->stencilTest = true;
- }
- void DeviceGraphics::setStencilFunc(StencilFunc func, int ref, unsigned int mask)
- {
- _nextState->stencilSeparation = false;
- _nextState->stencilFuncFront = _nextState->stencilFuncBack = func;
- _nextState->stencilRefFront = _nextState->stencilRefBack = ref;
- _nextState->stencilMaskFront = _nextState->stencilMaskBack = mask;
- }
- void DeviceGraphics::setStencilFuncFront(StencilFunc func, int ref, unsigned int mask)
- {
- _nextState->stencilSeparation = true;
- _nextState->stencilFuncFront = func;
- _nextState->stencilRefFront = ref;
- _nextState->stencilMaskFront = mask;
- }
- void DeviceGraphics::setStencilFuncBack(StencilFunc func, int ref, unsigned int mask)
- {
- _nextState->stencilSeparation = true;
- _nextState->stencilFuncBack = func;
- _nextState->stencilRefBack = ref;
- _nextState->stencilMaskBack = mask;
- }
- void DeviceGraphics::setStencilOp(StencilOp failOp, StencilOp zFailOp, StencilOp zPassOp, unsigned int writeMask)
- {
- _nextState->stencilFailOpFront = _nextState->stencilFailOpBack = failOp;
- _nextState->stencilZFailOpFront = _nextState->stencilZFailOpBack = zFailOp;
- _nextState->stencilZPassOpFront = _nextState->stencilZPassOpBack = zPassOp;
- _nextState->stencilWriteMaskFront = _nextState->stencilWriteMaskBack = writeMask;
- }
- void DeviceGraphics::setStencilOpFront(StencilOp failOp, StencilOp zFailOp, StencilOp zPassOp, unsigned int writeMask)
- {
- _nextState->stencilSeparation = true;
- _nextState->stencilFailOpFront = failOp;
- _nextState->stencilZFailOpFront = zFailOp;
- _nextState->stencilZPassOpFront = zPassOp;
- _nextState->stencilWriteMaskFront = writeMask;
- }
- void DeviceGraphics::setStencilOpBack(StencilOp failOp, StencilOp zFailOp, StencilOp zPassOp, unsigned int writeMask)
- {
- _nextState->stencilSeparation = true;
- _nextState->stencilFailOpBack = failOp;
- _nextState->stencilZFailOpBack = zFailOp;
- _nextState->stencilZPassOpBack = zPassOp;
- _nextState->stencilWriteMaskBack = writeMask;
- }
- void DeviceGraphics::setDepthFunc(DepthFunc func)
- {
- _nextState->depthFunc = func;
- }
- void DeviceGraphics::setBlendColor(uint32_t rgba)
- {
- _nextState->blendColor = rgba;
- }
- void DeviceGraphics::setBlendColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
- {
- _nextState->blendColor = (r << 24) | (g << 16) | (b << 8) | a;
- }
- void DeviceGraphics::setBlendFunc(BlendFactor src, BlendFactor dst)
- {
- _nextState->blendSeparation = false;
- _nextState->blendSrc = src;
- _nextState->blendDst = dst;
- }
- void DeviceGraphics::setBlendFuncSeparate(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha, BlendFactor dstAlpha)
- {
- _nextState->blendSeparation = true;
- _nextState->blendSrc = srcRGB;
- _nextState->blendDst = dstRGB;
- _nextState->blendSrcAlpha = srcAlpha;
- _nextState->blendDstAlpha = dstAlpha;
- }
- void DeviceGraphics::setBlendEquation(BlendOp mode)
- {
- _nextState->blendSeparation = false;
- _nextState->blendEq = mode;
- }
- void DeviceGraphics::setBlendEquationSeparate(BlendOp modeRGB, BlendOp modeAlpha)
- {
- _nextState->blendSeparation = true;
- _nextState->blendEq = modeRGB;
- _nextState->blendAlphaEq = modeAlpha;
- }
- void DeviceGraphics::setCullMode(CullMode mode)
- {
- _nextState->cullMode = mode;
- }
- void DeviceGraphics::setVertexBuffer(int stream, VertexBuffer* buffer, int start /*= 0*/)
- {
- _nextState->setVertexBuffer(stream, buffer);
- _nextState->setVertexBufferOffset(stream, start);
- if (_nextState->maxStream < stream) {
- _nextState->maxStream = stream;
- }
- }
- void DeviceGraphics::setIndexBuffer(IndexBuffer *buffer)
- {
- _nextState->setIndexBuffer(buffer);
- }
- void DeviceGraphics::setProgram(Program *program)
- {
- _nextState->setProgram(program);
- }
- void DeviceGraphics::setTexture(size_t hashName, Texture* texture, int slot)
- {
- if (slot >= _caps.maxTextureUnits)
- {
- RENDERER_LOGW("Can not set texture %zu at stage %d, max texture exceed: %d",
- hashName, slot, _caps.maxTextureUnits);
- return;
- }
-
- _nextState->setTexture(slot, texture);
- setUniformi(hashName, slot);
- }
- void DeviceGraphics::setTextureArray(size_t hashName, const std::vector<Texture*>& textures, const std::vector<int>& slots)
- {
- auto len = textures.size();
- if (len >= _caps.maxTextureUnits)
- {
- RENDERER_LOGW("Can not set %d textures for %zu, max texture exceed: %d",
- (int)len, hashName, _caps.maxTextureUnits);
- return;
- }
- for (size_t i = 0; i < len; ++i)
- {
- auto slot = slots[i];
- _nextState->setTexture(slot, textures[i]);
- }
-
- setUniformiv(hashName, slots.size(), slots.data(), slots.size());
- }
- void DeviceGraphics::setPrimitiveType(PrimitiveType type)
- {
- _nextState->primitiveType = type;
- }
- void DeviceGraphics::draw(size_t base, GLsizei count)
- {
- commitBlendStates();
- commitDepthStates();
- commitStencilStates();
- commitCullMode();
- commitVertexBuffer();
-
- auto nextIndexBuffer = _nextState->getIndexBuffer();
- if (_currentState->getIndexBuffer() != nextIndexBuffer)
- {
- GL_CHECK(ccBindBuffer(GL_ELEMENT_ARRAY_BUFFER, nextIndexBuffer ? nextIndexBuffer->getHandle() : 0));
- }
-
- //commit program
- bool programDirty = false;
- if (_currentState->getProgram() != _nextState->getProgram())
- {
- if (_nextState->getProgram()->isLinked())
- {
- GL_CHECK(glUseProgram(_nextState->getProgram()->getHandle()));
- }
- else
- RENDERER_LOGW("Failed to use program: has not linked yet.");
-
- programDirty = true;
- }
-
- commitTextures();
-
- //commit uniforms
- const auto& uniformsInfo = _nextState->getProgram()->getUniforms();
- for (const auto& uniformInfo : uniformsInfo)
- {
- auto iter = _uniforms.find(uniformInfo.hashName);
- if (_uniforms.end() == iter)
- continue;
-
- auto& uniform = iter->second;
- if (!programDirty && !uniform.dirty)
- continue;
-
- uniform.dirty = false;
- uniformInfo.setUniform(uniform.value, uniform.elementType, uniform.count);
- }
-
- // draw primitives
- if (nextIndexBuffer)
- {
- GL_CHECK(glDrawElements(ENUM_CLASS_TO_GLENUM(_nextState->primitiveType),
- count,
- ENUM_CLASS_TO_GLENUM(nextIndexBuffer->getFormat()),
- (GLvoid *)(base * nextIndexBuffer->getBytesPerIndex())));
- }
- else
- {
- GL_CHECK(glDrawArrays(ENUM_CLASS_TO_GLENUM(_nextState->primitiveType), (GLint)base, count));
- }
-
- _drawCalls++;
-
- auto temp = _nextState;
- _nextState = _currentState;
- _currentState = temp;
-
- _nextState->reset();
- }
- void DeviceGraphics::setUniform(size_t hashName, const void* v, size_t bytes, UniformElementType elementType, size_t uniformCount)
- {
- auto iter = _uniforms.find(hashName);
- if (iter == _uniforms.end())
- {
- _uniforms[hashName] = Uniform(v, bytes, elementType, uniformCount);
- }
- else
- {
- auto& uniform = iter->second;
- uniform.dirty = true;
- uniform.setValue(v, bytes, uniformCount);
- }
- }
- void DeviceGraphics::setUniformi(size_t hashName, int i1)
- {
- setUniform(hashName, &i1, sizeof(int), UniformElementType::INT);
- }
- void DeviceGraphics::setUniformi(size_t hashName, int i1, int i2)
- {
- int tempValue[] = {i1, i2};
- setUniform(hashName, tempValue, 2 * sizeof(int), UniformElementType::INT);
- }
- void DeviceGraphics::setUniformi(size_t hashName, int i1, int i2, int i3)
- {
- int tempValue[] = {i1, i2, i3};
- setUniform(hashName, tempValue, 3 * sizeof(int), UniformElementType::INT);
- }
- void DeviceGraphics::setUniformi(size_t hashName, int i1, int i2, int i3, int i4)
- {
- int tempValue[] = {i1, i2, i3, i4};
- setUniform(hashName, tempValue, 4 * sizeof(int), UniformElementType::INT);
- }
- void DeviceGraphics::setUniformiv(size_t hashName, size_t elementCount, const int* value, size_t uniformCount)
- {
- setUniform(hashName, value, elementCount * sizeof(int), UniformElementType::INT, uniformCount);
- }
- void DeviceGraphics::setUniformf(size_t hashName, float f1)
- {
- setUniform(hashName, &f1, sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformf(size_t hashName, float f1, float f2)
- {
- float tempValue[] = {f1, f2};
- setUniform(hashName, tempValue, 2 * sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformf(size_t hashName, float f1, float f2, float f3)
- {
- float tempValue[] = {f1, f2, f3};
- setUniform(hashName, tempValue, 3 * sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformf(size_t hashName, float f1, float f2, float f3, float f4)
- {
- float tempValue[] = {f1, f2, f3, f4};
- setUniform(hashName, tempValue, 4 * sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformfv(size_t hashName, size_t elementCount, const float* value, size_t uniformCount)
- {
- setUniform(hashName, value, elementCount * sizeof(float), UniformElementType::FLOAT, uniformCount);
- }
- void DeviceGraphics::setUniformVec2(size_t hashName, const cocos2d::Vec2& value)
- {
- setUniform(hashName, &value, sizeof(Vec2), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformVec3(size_t hashName, const cocos2d::Vec3& value)
- {
- setUniform(hashName, &value, sizeof(Vec3), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformVec4(size_t hashName, const cocos2d::Vec4& value)
- {
- setUniform(hashName, &value, sizeof(Vec4), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformMat2(size_t hashName, float* value)
- {
- setUniform(hashName, value, 4 * sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformMat3(size_t hashName, float* value)
- {
- setUniform(hashName, value, 9 * sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformMat4(size_t hashName, float* value)
- {
- setUniform(hashName, value, 16 * sizeof(float), UniformElementType::FLOAT);
- }
- void DeviceGraphics::setUniformMat4(size_t hashName, const cocos2d::Mat4& value)
- {
- setUniform(hashName, value.m, 16 * sizeof(float), UniformElementType::FLOAT);
- }
- //
- // Priviate funcitons.
- //
- DeviceGraphics::DeviceGraphics()
- : _vx(0)
- , _vy(0)
- , _vw(0)
- , _vh(0)
- , _sx(0)
- , _sy(0)
- , _sw(0)
- , _sh(0)
- , _frameBuffer(nullptr)
- {
- initCaps();
- initStates();
-
- _newAttributes.resize(_caps.maxVertexAttributes);
- _enabledAtrributes.resize(_caps.maxVertexAttributes);
-
-
- _currentState = new State();
- _nextState = new State();
-
- // Make sure _currentState and _nextState have enough sapce for textures.
- _currentState->setTexture(_caps.maxTextureUnits, nullptr);
- _nextState->setTexture(_caps.maxTextureUnits, nullptr);
-
- glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFbo);
- }
- DeviceGraphics::~DeviceGraphics()
- {
- RENDERER_SAFE_RELEASE(_frameBuffer);
-
- delete _currentState;
- delete _nextState;
-
- _currentState = _nextState = nullptr;
- }
- void DeviceGraphics::initCaps()
- {
- GL_CHECK(glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &_caps.maxVextexTextures));
- GL_CHECK(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &_caps.maxVertexAttributes));
- // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS
- // because desktop GL's corresponding queries return the number of components
- // whereas GLES2 return the number of vectors (each vector has 4 components).
- // Therefore, the value returned by desktop GL needs to be divided by 4.
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
- GL_CHECK(glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &_caps.maxFragUniforms));
- _caps.maxFragUniforms /= 4;
- #else
- GL_CHECK(glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &_caps.maxFragUniforms));
- #endif
- GL_CHECK(glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_caps.maxTextureUnits));
-
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
- // IDEA: how to get these infomations
- _caps.maxColorAttatchments = 1;
- _caps.maxDrawBuffers = 1;
- #else
- GL_CHECK(glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &_caps.maxColorAttatchments));
- GL_CHECK(glGetIntegerv(GL_MAX_DRAW_BUFFERS, &_caps.maxDrawBuffers));
- #endif
- RENDERER_LOGD("Device caps: maxVextexTextures: %d, maxFragUniforms: %d, maxTextureUints: %d, maxVertexAttributes: %d, maxDrawBuffers: %d, maxColorAttatchments: %d",
- _caps.maxVextexTextures, _caps.maxFragUniforms, _caps.maxTextureUnits, _caps.maxVertexAttributes, _caps.maxDrawBuffers, _caps.maxColorAttatchments);
- }
- void DeviceGraphics::initStates()
- {
- GL_CHECK(glDisable(GL_BLEND));
- GL_CHECK(glBlendFunc(GL_ONE, GL_ZERO));
- GL_CHECK(glBlendEquation(GL_FUNC_ADD));
- GL_CHECK(glBlendColor(1, 1, 1, 1));
-
- GL_CHECK(glColorMask(true, true, true, true));
-
- GL_CHECK(glEnable(GL_CULL_FACE));
- GL_CHECK(glCullFace(GL_BACK));
-
- GL_CHECK(glDisable(GL_DEPTH_TEST));
- GL_CHECK(glDepthFunc(GL_LESS));
- GL_CHECK(glDepthMask(GL_FALSE));
- GL_CHECK(glDisable(GL_POLYGON_OFFSET_FILL));
- GL_CHECK(glDepthRange(0, 1));
-
- GL_CHECK(glDisable(GL_STENCIL_TEST));
- GL_CHECK(glStencilFunc(GL_ALWAYS, 0, 0xff));
- GL_CHECK(glStencilMask(0xff));
- GL_CHECK(glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
-
- GL_CHECK(glClearDepth(1));
- GL_CHECK(glClearColor(0, 0, 0, 0));
- GL_CHECK(glClearStencil(0));
-
- GL_CHECK(glDisable(GL_SCISSOR_TEST));
- }
- void DeviceGraphics::restoreTexture(uint32_t index)
- {
- auto texture = _currentState->getTexture(index);
- if (texture)
- {
- GL_CHECK(glBindTexture(texture->getTarget(), texture->getHandle()));
- }
- else
- {
- GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
- }
- }
- void DeviceGraphics::restoreIndexBuffer()
- {
- auto ib = _currentState->getIndexBuffer();
- GL_CHECK(ccBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib ? ib->getHandle(): 0));
- }
- void DeviceGraphics::commitBlendStates()
- {
- if (_currentState->blend != _nextState->blend)
- {
- if (!_nextState->blend)
- {
- glDisable(GL_BLEND);
- return;
- }
- glEnable(GL_BLEND);
-
- if (_nextState->blendSrc == BlendFactor::CONSTANT_COLOR ||
- _nextState->blendSrc == BlendFactor::ONE_MINUS_CONSTANT_COLOR ||
- _nextState->blendDst == BlendFactor::CONSTANT_COLOR ||
- _nextState->blendDst == BlendFactor::ONE_MINUS_CONSTANT_COLOR)
- {
- GL_CHECK(glBlendColor((_nextState->blendColor >> 24) / 255.f,
- (_nextState->blendColor >> 16 & 0xff) / 255.f,
- (_nextState->blendColor >> 8 & 0xff) / 255.f,
- (_nextState->blendColor & 0xff) / 255.f));
-
- }
-
- if (_nextState->blendSeparation)
- {
- GL_CHECK(glBlendFuncSeparate(ENUM_CLASS_TO_GLENUM(_nextState->blendSrc),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDst),
- ENUM_CLASS_TO_GLENUM(_nextState->blendSrcAlpha),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDstAlpha)));
- GL_CHECK(glBlendEquationSeparate(ENUM_CLASS_TO_GLENUM(_nextState->blendEq),
- ENUM_CLASS_TO_GLENUM(_nextState->blendAlphaEq)));
- }
- else
- {
- GL_CHECK(glBlendFunc(ENUM_CLASS_TO_GLENUM(_nextState->blendSrc),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDst)));
- GL_CHECK(glBlendEquation(ENUM_CLASS_TO_GLENUM(_nextState->blendEq)));
- }
-
- return;
- }
-
- if (_nextState->blend == false)
- return;
-
- if (_currentState->blendColor != _nextState->blendColor)
- glBlendColor((_nextState->blendColor >> 24) / 255.f,
- (_nextState->blendColor >> 16 & 0xff) / 255.f,
- (_nextState->blendColor >> 8 & 0xff) / 255.f,
- (_nextState->blendColor & 0xff) / 255.f);
-
- if (_currentState->blendSeparation != _nextState->blendSeparation)
- {
- if (_nextState->blendSeparation)
- {
- GL_CHECK(glBlendFuncSeparate(ENUM_CLASS_TO_GLENUM(_nextState->blendSrc),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDst),
- ENUM_CLASS_TO_GLENUM(_nextState->blendSrcAlpha),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDstAlpha)));
- GL_CHECK(glBlendEquationSeparate(ENUM_CLASS_TO_GLENUM(_nextState->blendEq),
- ENUM_CLASS_TO_GLENUM(_nextState->blendAlphaEq)));
- }
- else
- {
- GL_CHECK(glBlendFunc(ENUM_CLASS_TO_GLENUM(_nextState->blendSrc),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDst)));
- GL_CHECK(glBlendEquation(ENUM_CLASS_TO_GLENUM(_nextState->blendEq)));
- }
-
- return;
- }
-
- if (_nextState->blendSeparation)
- {
- if (_currentState->blendSrc != _nextState->blendSrc ||
- _currentState->blendDst != _nextState->blendDst ||
- _currentState->blendSrcAlpha != _nextState->blendSrcAlpha ||
- _currentState->blendDstAlpha != _nextState->blendDstAlpha)
- {
- GL_CHECK(glBlendFuncSeparate(ENUM_CLASS_TO_GLENUM(_nextState->blendSrc),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDst),
- ENUM_CLASS_TO_GLENUM(_nextState->blendSrcAlpha),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDstAlpha)));
- }
- }
-
- if (_currentState->blendEq != _nextState->blendEq ||
- _currentState->blendAlphaEq != _nextState->blendAlphaEq)
- {
- GL_CHECK(glBlendEquationSeparate(ENUM_CLASS_TO_GLENUM(_nextState->blendEq),
- ENUM_CLASS_TO_GLENUM(_nextState->blendAlphaEq)));
- }
- else
- {
- if (_currentState->blendSrc != _nextState->blendSrc ||
- _currentState->blendDst != _nextState->blendDst)
- {
- GL_CHECK(glBlendFunc(ENUM_CLASS_TO_GLENUM(_nextState->blendSrc),
- ENUM_CLASS_TO_GLENUM(_nextState->blendDst)));
- }
-
- if (_currentState->blendEq != _nextState->blendEq)
- {
- GL_CHECK(glBlendEquation(ENUM_CLASS_TO_GLENUM(_nextState->blendEq)));
- }
- }
- }
- void DeviceGraphics::commitDepthStates()
- {
- if (_currentState->depthTest != _nextState->depthTest)
- {
- if (!_nextState->depthTest)
- {
- glDisable(GL_DEPTH_TEST);
- return;
- }
-
- GL_CHECK(glEnable(GL_DEPTH_TEST));
- GL_CHECK(glDepthFunc(ENUM_CLASS_TO_GLENUM(_nextState->depthFunc)));
- GL_CHECK(glDepthMask(_nextState->depthWrite ? GL_TRUE : GL_FALSE));
-
- return;
- }
-
- if (_currentState->depthWrite != _nextState->depthWrite)
- {
- GL_CHECK(glDepthMask(_nextState->depthWrite ? GL_TRUE : GL_FALSE));
- }
-
- if (!_nextState->depthTest)
- {
- if (_nextState->depthWrite)
- {
- _nextState->depthTest = true;
- _nextState->depthFunc = DepthFunc::ALWAYS;
-
- GL_CHECK(glEnable(GL_DEPTH_TEST));
- GL_CHECK(glDepthFunc(ENUM_CLASS_TO_GLENUM(_nextState->depthFunc)));
- }
-
- return;
- }
-
- if (_currentState->depthFunc != _nextState->depthFunc)
- {
- GL_CHECK(glDepthFunc(ENUM_CLASS_TO_GLENUM(_nextState->depthFunc)));
- }
- }
- void DeviceGraphics::commitStencilStates()
- {
- if (_currentState->stencilTest != _nextState->stencilTest)
- {
- if (!_nextState->stencilTest)
- {
- glDisable(GL_STENCIL_TEST);
- return;
- }
-
- glEnable(GL_STENCIL_TEST);
-
- if (_nextState->stencilSeparation)
- {
- GL_CHECK(glStencilFuncSeparate(GL_FRONT,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskFront)));
- GL_CHECK(glStencilMaskSeparate(GL_FRONT, ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskFront)));
- GL_CHECK(glStencilOpSeparate(GL_FRONT,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpFront)));
- GL_CHECK(glStencilFuncSeparate(GL_BACK,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskBack)));
- GL_CHECK(glStencilMaskSeparate(GL_BACK, ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskBack)));
- GL_CHECK(glStencilOpSeparate(GL_BACK,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpBack)));
- }
- else
- {
- GL_CHECK(glStencilFunc(ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskFront)));
- GL_CHECK(glStencilMask(ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskFront)));
- GL_CHECK(glStencilOp(ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpFront)));
- }
-
- return;
- }
-
- if (!_nextState->stencilTest)
- return;
-
- if (_currentState->stencilSeparation != _nextState->stencilSeparation)
- {
- if (_nextState->stencilSeparation)
- {
- // front
- GL_CHECK(glStencilFuncSeparate(GL_FRONT,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskFront)));
- GL_CHECK(glStencilMaskSeparate(GL_FRONT, ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskFront)));
- GL_CHECK(glStencilOpSeparate(GL_FRONT,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpFront)));
-
- // back
- GL_CHECK(glStencilFuncSeparate(GL_BACK,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskBack)));
- GL_CHECK(glStencilMaskSeparate(GL_BACK, ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskBack)));
- GL_CHECK(glStencilOpSeparate(GL_BACK,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpBack)));
- }
- else
- {
- GL_CHECK(glStencilFunc(ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskFront)));
- GL_CHECK(glStencilMask(ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskFront)));
- GL_CHECK(glStencilOp(ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpFront)));
- }
-
- return;
- }
-
- if (_nextState->stencilSeparation)
- {
- // font
- if (_currentState->stencilFuncFront != _nextState->stencilFuncFront ||
- _currentState->stencilRefFront != _nextState->stencilRefFront ||
- _currentState->stencilMaskFront != _nextState->stencilMaskFront)
- {
- GL_CHECK(glStencilFuncSeparate(GL_FRONT,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskFront)));
- }
- if (_currentState->stencilWriteMaskFront != _nextState->stencilWriteMaskFront)
- {
- GL_CHECK(glStencilMaskSeparate(GL_FRONT, ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskFront)));
- }
- if (_currentState->stencilFailOpFront != _nextState->stencilFailOpFront ||
- _currentState->stencilZFailOpFront != _nextState->stencilZFailOpFront ||
- _currentState->stencilZPassOpFront != _nextState->stencilZPassOpFront)
- {
- GL_CHECK(glStencilOpSeparate(GL_FRONT,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpFront)));
- }
-
- // back
- if (_currentState->stencilFuncBack != _nextState->stencilFuncBack ||
- _currentState->stencilRefBack != _nextState->stencilRefBack ||
- _currentState->stencilMaskBack != _nextState->stencilMaskBack)
- {
- GL_CHECK(glStencilFuncSeparate(GL_BACK,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskBack)));
- }
- if (_currentState->stencilWriteMaskBack != _nextState->stencilWriteMaskBack)
- GL_CHECK(glStencilMaskSeparate(GL_BACK, ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskBack)));
- if (_currentState->stencilFailOpBack != _nextState->stencilFailOpBack ||
- _currentState->stencilZFailOpBack != _nextState->stencilZFailOpBack ||
- _currentState->stencilZPassOpBack != _nextState->stencilZPassOpBack)
- {
- GL_CHECK(glStencilOpSeparate(GL_BACK,
- ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpBack),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpBack)));
- }
- }
- else
- {
- if (_currentState->stencilFuncFront != _nextState->stencilFuncFront ||
- _currentState->stencilRefFront != _nextState->stencilRefFront ||
- _currentState->stencilMaskFront != _nextState->stencilMaskFront)
- {
- GL_CHECK(glStencilFunc(ENUM_CLASS_TO_GLENUM(_nextState->stencilFuncFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilRefFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilMaskFront)));
- }
-
- if (_currentState->stencilWriteMaskFront != _nextState->stencilWriteMaskFront)
- {
- GL_CHECK(glStencilMask(ENUM_CLASS_TO_GLENUM(_nextState->stencilWriteMaskFront)));
- }
-
- if (_currentState->stencilFailOpFront != _nextState->stencilFailOpFront ||
- _currentState->stencilZFailOpFront != _nextState->stencilZFailOpFront ||
- _currentState->stencilZPassOpFront != _nextState->stencilZPassOpFront)
- {
- GL_CHECK(glStencilOp(ENUM_CLASS_TO_GLENUM(_nextState->stencilFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZFailOpFront),
- ENUM_CLASS_TO_GLENUM(_nextState->stencilZPassOpFront)));
- }
- }
- }
- void DeviceGraphics::commitCullMode()
- {
- if (_currentState->cullMode == _nextState->cullMode)
- return;
-
- if (_nextState->cullMode == CullMode::NONE)
- {
- GL_CHECK(glDisable(GL_CULL_FACE));
- return;
- }
-
- GL_CHECK(glEnable(GL_CULL_FACE));
- GL_CHECK(glCullFace(ENUM_CLASS_TO_GLENUM(_nextState->cullMode)));
- }
- void DeviceGraphics::commitVertexBuffer()
- {
- if (-1 == _nextState->maxStream)
- {
- RENDERER_LOGW("VertexBuffer not assigned, please call setVertexBuffer before every draw.");
- return;
- }
-
- bool attrsDirty = false;
- if (_currentState->maxStream != _nextState->maxStream)
- attrsDirty = true;
- else if (_currentState->getProgram() != _nextState->getProgram())
- attrsDirty = true;
- else
- {
- for (int i = 0; i < _nextState->maxStream + 1; ++i)
- {
- if (_currentState->getVertexBuffer(i) != _nextState->getVertexBuffer(i) ||
- _currentState->getVertexBufferOffset(i) != _nextState->getVertexBufferOffset(i))
- {
- attrsDirty = true;
- break;
- }
- }
- }
-
- if (attrsDirty)
- {
- for (int i = 0; i < _caps.maxVertexAttributes; ++i)
- _newAttributes[i] = 0;
-
- for (int i = 0; i < _nextState->maxStream + 1; ++i)
- {
- auto vb = _nextState->getVertexBuffer(i);
- if (!vb)
- continue;
-
- GL_CHECK(ccBindBuffer(GL_ARRAY_BUFFER, vb->getHandle()));
-
- auto vboffset = _nextState->getVertexBufferOffset(i);
- const auto& attributes = _nextState->getProgram()->getAttributes();
- auto usedAttriLen = attributes.size();
- for (int j = 0; j < usedAttriLen; ++j)
- {
- const auto& attr = attributes[j];
- const auto* el = vb->getFormat().getElement(attr.hashName);
- if (!el || !el->isValid())
- {
- RENDERER_LOGW("Can not find vertex attribute: %s", attr.name.c_str());
- continue;
- }
-
- if (0 == _enabledAtrributes[attr.location])
- {
- GL_CHECK(ccEnableVertexAttribArray(attr.location));
- _enabledAtrributes[attr.location] = 1;
- }
- _newAttributes[attr.location] = 1;
-
- // glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
- GL_CHECK(ccVertexAttribPointer(attr.location,
- el->num,
- ENUM_CLASS_TO_GLENUM(el->type),
- el->normalize,
- el->stride,
- (GLvoid*)(el->offset + vboffset * el->stride)));
- }
- }
-
- // Disable unused attributes.
- for (int i = 0; i < _caps.maxVertexAttributes; ++i)
- {
- if (_enabledAtrributes[i] != _newAttributes[i])
- {
- GL_CHECK(ccDisableVertexAttribArray(i));
- _enabledAtrributes[i] = 0;
- }
- }
- }
- }
- void DeviceGraphics::commitTextures()
- {
- const auto& curTextureUnits = _currentState->getTextureUnits();
- int curTextureSize = static_cast<int>(curTextureUnits.size());
- const auto& nextTextureUnits = _nextState->getTextureUnits();
- int capacity = static_cast<int>(nextTextureUnits.size());
- for (int i = 0; i < capacity; ++i)
- {
- if (i >= curTextureSize || curTextureUnits[i] != nextTextureUnits[i])
- {
- auto texture = nextTextureUnits[i];
- if (texture)
- {
- GL_CHECK(glActiveTexture(GL_TEXTURE0 + i));
- GL_CHECK(glBindTexture(texture->getTarget(),
- texture->getHandle()));
- }
- }
- }
- }
- //
- // Uniform
- //
- DeviceGraphics::Uniform::Uniform()
- : dirty(true)
- , elementType(UniformElementType::FLOAT)
- {}
- DeviceGraphics::Uniform::Uniform(const void* v, size_t bytes, UniformElementType elementType_, size_t count)
- : dirty(true)
- , elementType(elementType_)
- {
- setValue(v, bytes, count);
- }
- DeviceGraphics::Uniform::Uniform(Uniform&& h)
- {
- if (this == &h)
- return;
- if (value != nullptr)
- {
- free(value);
- }
- value = h.value;
- count = h.count;
- h.value = nullptr;
-
- dirty = h.dirty;
- elementType = h.elementType;
- }
- DeviceGraphics::Uniform::~Uniform()
- {
- if (value)
- {
- free(value);
- value = nullptr;
- }
- }
- DeviceGraphics::Uniform& DeviceGraphics::Uniform::operator=(Uniform&& h)
- {
- if (this == &h)
- return *this;
-
- dirty = h.dirty;
- if (value != nullptr)
- {
- free(value);
- }
- value = h.value;
- count = h.count;
- h.value = nullptr;
- elementType = h.elementType;
-
- return *this;
- }
- void DeviceGraphics::Uniform::setValue(const void* v, size_t valueBytes, size_t uniformCount)
- {
- if (bytes != valueBytes || !value) {
- if (value)
- free(value);
- value = malloc(valueBytes);
-
- bytes = valueBytes;
- count = uniformCount;
- }
-
- memcpy(value, v, valueBytes);
- }
- RENDERER_END
|