no message

This commit is contained in:
gem
2025-02-18 15:21:31 +08:00
commit 2d133e56d7
1980 changed files with 465595 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Buffer.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "profiler/Profiler.h"
namespace cc {
namespace gfx {
GLES3Buffer::GLES3Buffer() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3Buffer::~GLES3Buffer() {
destroy();
}
void GLES3Buffer::doInit(const BufferInfo & /*info*/) {
_gpuBuffer = ccnew GLES3GPUBuffer;
_gpuBuffer->usage = _usage;
_gpuBuffer->memUsage = _memUsage;
_gpuBuffer->size = _size;
_gpuBuffer->stride = _stride;
_gpuBuffer->count = _count;
if (hasFlag(_usage, BufferUsageBit::INDIRECT)) {
_gpuBuffer->indirects.resize(_count);
}
cmdFuncGLES3CreateBuffer(GLES3Device::getInstance(), _gpuBuffer);
GLES3Device::getInstance()->getMemoryStatus().bufferSize += _size;
CC_PROFILE_MEMORY_INC(Buffer, _size);
}
void GLES3Buffer::doInit(const BufferViewInfo &info) {
auto *buffer = static_cast<GLES3Buffer *>(info.buffer);
_gpuBuffer = ccnew GLES3GPUBuffer;
_gpuBuffer->usage = _usage;
_gpuBuffer->memUsage = _memUsage;
_gpuBuffer->size = _size;
_gpuBuffer->stride = _stride;
_gpuBuffer->count = _count;
_gpuBuffer->glTarget = buffer->_gpuBuffer->glTarget;
_gpuBuffer->glBuffer = buffer->_gpuBuffer->glBuffer;
_gpuBuffer->glOffset = info.offset;
_gpuBuffer->buffer = buffer->_gpuBuffer->buffer;
_gpuBuffer->indirects = buffer->_gpuBuffer->indirects;
}
void GLES3Buffer::doDestroy() {
if (_gpuBuffer) {
if (!_isBufferView) {
cmdFuncGLES3DestroyBuffer(GLES3Device::getInstance(), _gpuBuffer);
GLES3Device::getInstance()->getMemoryStatus().bufferSize -= _size;
CC_PROFILE_MEMORY_DEC(Buffer, _size);
}
delete _gpuBuffer;
_gpuBuffer = nullptr;
}
}
void GLES3Buffer::doResize(uint32_t size, uint32_t count) {
GLES3Device::getInstance()->getMemoryStatus().bufferSize -= _size;
CC_PROFILE_MEMORY_DEC(Buffer, _size);
_gpuBuffer->size = size;
_gpuBuffer->count = count;
cmdFuncGLES3ResizeBuffer(GLES3Device::getInstance(), _gpuBuffer);
GLES3Device::getInstance()->getMemoryStatus().bufferSize += size;
CC_PROFILE_MEMORY_INC(Buffer, size);
}
void GLES3Buffer::update(const void *buffer, uint32_t size) {
CC_PROFILE(GLES3BufferUpdate);
cmdFuncGLES3UpdateBuffer(GLES3Device::getInstance(), _gpuBuffer, buffer, 0U, size);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,54 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXBuffer.h"
namespace cc {
namespace gfx {
struct GLES3GPUBuffer;
class CC_GLES3_API GLES3Buffer final : public Buffer {
public:
GLES3Buffer();
~GLES3Buffer() override;
void update(const void *buffer, uint32_t size) override;
inline GLES3GPUBuffer *gpuBuffer() const { return _gpuBuffer; }
protected:
void doInit(const BufferInfo &info) override;
void doInit(const BufferViewInfo &info) override;
void doDestroy() override;
void doResize(uint32_t size, uint32_t count) override;
GLES3GPUBuffer *_gpuBuffer = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,506 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Buffer.h"
#include "GLES3CommandBuffer.h"
#include "GLES3Commands.h"
#include "GLES3DescriptorSet.h"
#include "GLES3Device.h"
#include "GLES3Framebuffer.h"
#include "GLES3InputAssembler.h"
#include "GLES3PipelineState.h"
#include "GLES3QueryPool.h"
#include "GLES3RenderPass.h"
#include "GLES3Texture.h"
#include "profiler/Profiler.h"
#include "states/GLES3GeneralBarrier.h"
namespace cc {
namespace gfx {
GLES3CommandBuffer::GLES3CommandBuffer() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3CommandBuffer::~GLES3CommandBuffer() {
destroy();
}
void GLES3CommandBuffer::doInit(const CommandBufferInfo & /*info*/) {
_cmdAllocator = ccnew GLES3GPUCommandAllocator;
_curCmdPackage = ccnew GLES3CmdPackage;
size_t setCount = GLES3Device::getInstance()->bindingMappingInfo().setIndices.size();
_curGPUDescriptorSets.resize(setCount);
_curDynamicOffsets.resize(setCount);
}
void GLES3CommandBuffer::doDestroy() {
if (!_cmdAllocator) return;
_cmdAllocator->clearCmds(_curCmdPackage);
CC_SAFE_DELETE(_curCmdPackage);
while (!_pendingPackages.empty()) {
GLES3CmdPackage *package = _pendingPackages.front();
_cmdAllocator->clearCmds(package);
CC_SAFE_DELETE(package);
_pendingPackages.pop();
}
while (!_freePackages.empty()) {
GLES3CmdPackage *package = _freePackages.front();
_cmdAllocator->clearCmds(package);
CC_SAFE_DELETE(package);
_freePackages.pop();
}
_cmdAllocator->reset();
CC_SAFE_DELETE(_cmdAllocator);
}
void GLES3CommandBuffer::begin(RenderPass * /*renderPass*/, uint32_t /*subpass*/, Framebuffer * /*frameBuffer*/) {
_curGPUPipelineState = nullptr;
_curGPUInputAssember = nullptr;
_curGPUDescriptorSets.assign(_curGPUDescriptorSets.size(), nullptr);
_numDrawCalls = 0;
_numInstances = 0;
_numTriangles = 0;
_cmdAllocator->clearCmds(_curCmdPackage);
}
void GLES3CommandBuffer::end() {
if (_isStateInvalid) {
bindStates();
}
_pendingPackages.push(_curCmdPackage);
if (!_freePackages.empty()) {
_curCmdPackage = _freePackages.front();
_freePackages.pop();
} else {
_curCmdPackage = ccnew GLES3CmdPackage;
}
}
void GLES3CommandBuffer::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const * /*secondaryCBs*/, uint32_t /*secondaryCBCount*/) {
_curSubpassIdx = 0U;
GLES3CmdBeginRenderPass *cmd = _cmdAllocator->beginRenderPassCmdPool.alloc();
cmd->subpassIdx = _curSubpassIdx;
cmd->gpuRenderPass = static_cast<GLES3RenderPass *>(renderPass)->gpuRenderPass();
cmd->gpuFBO = static_cast<GLES3Framebuffer *>(fbo)->gpuFBO();
cmd->renderArea = renderArea;
size_t numClearColors = cmd->gpuRenderPass->colorAttachments.size();
memcpy(cmd->clearColors, colors, numClearColors * sizeof(Color));
cmd->clearDepth = depth;
cmd->clearStencil = stencil;
_curCmdPackage->beginRenderPassCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::BEGIN_RENDER_PASS);
_curDynamicStates.viewport = {renderArea.x, renderArea.y, renderArea.width, renderArea.height};
_curDynamicStates.scissor = renderArea;
}
void GLES3CommandBuffer::endRenderPass() {
_curCmdPackage->cmds.push(GLESCmdType::END_RENDER_PASS);
}
void GLES3CommandBuffer::nextSubpass() {
_curCmdPackage->cmds.push(GLESCmdType::END_RENDER_PASS);
GLES3CmdBeginRenderPass *cmd = _cmdAllocator->beginRenderPassCmdPool.alloc();
cmd->subpassIdx = ++_curSubpassIdx;
_curCmdPackage->beginRenderPassCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::BEGIN_RENDER_PASS);
}
void GLES3CommandBuffer::insertMarker(const MarkerInfo &marker) {
std::ignore = marker;
}
void GLES3CommandBuffer::beginMarker(const MarkerInfo &marker) {
std::ignore = marker;
}
void GLES3CommandBuffer::endMarker() {
}
void GLES3CommandBuffer::bindPipelineState(PipelineState *pso) {
GLES3GPUPipelineState *gpuPipelineState = static_cast<GLES3PipelineState *>(pso)->gpuPipelineState();
if (_curGPUPipelineState != gpuPipelineState) {
_curGPUPipelineState = gpuPipelineState;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) {
CC_ASSERT(_curGPUDescriptorSets.size() > set);
GLES3GPUDescriptorSet *gpuDescriptorSet = static_cast<GLES3DescriptorSet *>(descriptorSet)->gpuDescriptorSet();
if (_curGPUDescriptorSets[set] != gpuDescriptorSet) {
_curGPUDescriptorSets[set] = gpuDescriptorSet;
_isStateInvalid = true;
}
if (dynamicOffsetCount) {
_curDynamicOffsets[set].assign(dynamicOffsets, dynamicOffsets + dynamicOffsetCount);
_isStateInvalid = true;
} else if (!_curDynamicOffsets[set].empty()) {
_curDynamicOffsets[set].assign(_curDynamicOffsets[set].size(), 0);
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::bindInputAssembler(InputAssembler *ia) {
_curGPUInputAssember = static_cast<GLES3InputAssembler *>(ia)->gpuInputAssembler();
_isStateInvalid = true;
}
void GLES3CommandBuffer::setViewport(const Viewport &vp) {
if ((_curDynamicStates.viewport.left != vp.left) ||
(_curDynamicStates.viewport.top != vp.top) ||
(_curDynamicStates.viewport.width != vp.width) ||
(_curDynamicStates.viewport.height != vp.height) ||
math::isNotEqualF(_curDynamicStates.viewport.minDepth, vp.minDepth) ||
math::isNotEqualF(_curDynamicStates.viewport.maxDepth, vp.maxDepth)) {
_curDynamicStates.viewport = vp;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::setScissor(const Rect &rect) {
if ((_curDynamicStates.scissor.x != rect.x) ||
(_curDynamicStates.scissor.y != rect.y) ||
(_curDynamicStates.scissor.width != rect.width) ||
(_curDynamicStates.scissor.height != rect.height)) {
_curDynamicStates.scissor = rect;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::setLineWidth(float width) {
if (math::isNotEqualF(_curDynamicStates.lineWidth, width)) {
_curDynamicStates.lineWidth = width;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::setDepthBias(float constant, float clamp, float slope) {
if (math::isNotEqualF(_curDynamicStates.depthBiasConstant, constant) ||
math::isNotEqualF(_curDynamicStates.depthBiasClamp, clamp) ||
math::isNotEqualF(_curDynamicStates.depthBiasSlope, slope)) {
_curDynamicStates.depthBiasConstant = constant;
_curDynamicStates.depthBiasClamp = clamp;
_curDynamicStates.depthBiasSlope = slope;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::setBlendConstants(const Color &constants) {
if (math::isNotEqualF(_curDynamicStates.blendConstant.x, constants.x) ||
math::isNotEqualF(_curDynamicStates.blendConstant.y, constants.y) ||
math::isNotEqualF(_curDynamicStates.blendConstant.z, constants.z) ||
math::isNotEqualF(_curDynamicStates.blendConstant.w, constants.w)) {
_curDynamicStates.blendConstant.x = constants.x;
_curDynamicStates.blendConstant.y = constants.y;
_curDynamicStates.blendConstant.z = constants.z;
_curDynamicStates.blendConstant.w = constants.w;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::setDepthBound(float minBounds, float maxBounds) {
if (math::isNotEqualF(_curDynamicStates.depthMinBounds, minBounds) ||
math::isNotEqualF(_curDynamicStates.depthMaxBounds, maxBounds)) {
_curDynamicStates.depthMinBounds = minBounds;
_curDynamicStates.depthMaxBounds = maxBounds;
_isStateInvalid = true;
}
}
void GLES3CommandBuffer::setStencilWriteMask(StencilFace face, uint32_t mask) {
auto update = [&](DynamicStencilStates &stencilState) {
if (stencilState.writeMask != mask) {
stencilState.writeMask = mask;
_isStateInvalid = true;
}
};
if (hasFlag(face, StencilFace::FRONT)) update(_curDynamicStates.stencilStatesFront);
if (hasFlag(face, StencilFace::BACK)) update(_curDynamicStates.stencilStatesBack);
}
void GLES3CommandBuffer::setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) {
auto update = [&](DynamicStencilStates &stencilState) {
if ((stencilState.reference != ref) ||
(stencilState.compareMask != mask)) {
stencilState.reference = ref;
stencilState.compareMask = mask;
_isStateInvalid = true;
}
};
if (hasFlag(face, StencilFace::FRONT)) update(_curDynamicStates.stencilStatesFront);
if (hasFlag(face, StencilFace::BACK)) update(_curDynamicStates.stencilStatesBack);
}
void GLES3CommandBuffer::draw(const DrawInfo &info) {
CC_PROFILE(GLES3CommandBufferDraw);
if (_isStateInvalid) {
bindStates();
}
GLES3CmdDraw *cmd = _cmdAllocator->drawCmdPool.alloc();
cmd->drawInfo = info;
_curCmdPackage->drawCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::DRAW);
++_numDrawCalls;
_numInstances += info.instanceCount;
if (_curGPUPipelineState) {
uint32_t indexCount = info.indexCount ? info.indexCount : info.vertexCount;
switch (_curGPUPipelineState->glPrimitive) {
case GL_TRIANGLES: {
_numTriangles += indexCount / 3 * std::max(info.instanceCount, 1U);
break;
}
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN: {
_numTriangles += (indexCount - 2) * std::max(info.instanceCount, 1U);
break;
}
default:
break;
}
}
}
void GLES3CommandBuffer::updateBuffer(Buffer *buff, const void *data, uint32_t size) {
GLES3GPUBuffer *gpuBuffer = static_cast<GLES3Buffer *>(buff)->gpuBuffer();
if (gpuBuffer) {
GLES3CmdUpdateBuffer *cmd = _cmdAllocator->updateBufferCmdPool.alloc();
cmd->gpuBuffer = gpuBuffer;
cmd->size = size;
cmd->buffer = static_cast<const uint8_t *>(data);
_curCmdPackage->updateBufferCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::UPDATE_BUFFER);
}
}
void GLES3CommandBuffer::copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
// should not copy texture in a secondary command buffer
}
void GLES3CommandBuffer::resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
// should not resolve texture in a secondary command buffer
}
void GLES3CommandBuffer::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) {
GLES3CmdBlitTexture *cmd = _cmdAllocator->blitTextureCmdPool.alloc();
if (srcTexture) cmd->gpuTextureSrcView = static_cast<GLES3Texture *>(srcTexture)->gpuTextureView();
if (dstTexture) cmd->gpuTextureDstView = static_cast<GLES3Texture *>(dstTexture)->gpuTextureView();
cmd->regions = regions;
cmd->count = count;
cmd->filter = filter;
_curCmdPackage->blitTextureCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::BLIT_TEXTURE);
}
void GLES3CommandBuffer::copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) {
GLES3GPUTexture *gpuTexture = static_cast<GLES3Texture *>(texture)->gpuTexture();
if (gpuTexture) {
GLES3CmdCopyBufferToTexture *cmd = _cmdAllocator->copyBufferToTextureCmdPool.alloc();
cmd->gpuTexture = gpuTexture;
cmd->regions = regions;
cmd->count = count;
cmd->buffers = buffers;
_curCmdPackage->copyBufferToTextureCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::COPY_BUFFER_TO_TEXTURE);
}
}
void GLES3CommandBuffer::execute(CommandBuffer *const *cmdBuffs, uint32_t count) {
CC_ABORT(); // Command 'execute' must be recorded in primary command buffers.
for (uint32_t i = 0; i < count; ++i) {
auto *cmdBuff = static_cast<GLES3CommandBuffer *>(cmdBuffs[i]);
GLES3CmdPackage *cmdPackage = cmdBuff->_pendingPackages.front();
for (uint32_t j = 0; j < cmdPackage->beginRenderPassCmds.size(); ++j) {
GLES3CmdBeginRenderPass *cmd = cmdPackage->beginRenderPassCmds[j];
++cmd->refCount;
_curCmdPackage->beginRenderPassCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->bindStatesCmds.size(); ++j) {
GLES3CmdBindStates *cmd = cmdPackage->bindStatesCmds[j];
++cmd->refCount;
_curCmdPackage->bindStatesCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->drawCmds.size(); ++j) {
GLES3CmdDraw *cmd = cmdPackage->drawCmds[j];
++cmd->refCount;
_curCmdPackage->drawCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->dispatchCmds.size(); ++j) {
GLES3CmdDispatch *cmd = cmdPackage->dispatchCmds[j];
++cmd->refCount;
_curCmdPackage->dispatchCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->barrierCmds.size(); ++j) {
GLES3CmdBarrier *cmd = cmdPackage->barrierCmds[j];
++cmd->refCount;
_curCmdPackage->barrierCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->updateBufferCmds.size(); ++j) {
GLES3CmdUpdateBuffer *cmd = cmdPackage->updateBufferCmds[j];
++cmd->refCount;
_curCmdPackage->updateBufferCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->copyBufferToTextureCmds.size(); ++j) {
GLES3CmdCopyBufferToTexture *cmd = cmdPackage->copyBufferToTextureCmds[j];
++cmd->refCount;
_curCmdPackage->copyBufferToTextureCmds.push(cmd);
}
for (uint32_t j = 0; j < cmdPackage->blitTextureCmds.size(); ++j) {
GLES3CmdBlitTexture *cmd = cmdPackage->blitTextureCmds[j];
++cmd->refCount;
_curCmdPackage->blitTextureCmds.push(cmd);
}
_curCmdPackage->cmds.concat(cmdPackage->cmds);
_numDrawCalls += cmdBuff->_numDrawCalls;
_numInstances += cmdBuff->_numInstances;
_numTriangles += cmdBuff->_numTriangles;
cmdBuff->_pendingPackages.pop();
cmdBuff->_freePackages.push(cmdPackage);
// current cmd allocator strategy will not work here: (but it doesn't matter anyways)
// allocators are designed to only free the cmds they allocated
// but here we are essentially 'transfering' the owner ship
// cmdBuff->_cmdAllocator->clearCmds(cmdPackage);
}
}
void GLES3CommandBuffer::bindStates() {
GLES3CmdBindStates *cmd = _cmdAllocator->bindStatesCmdPool.alloc();
cmd->gpuPipelineState = _curGPUPipelineState;
cmd->gpuInputAssembler = _curGPUInputAssember;
cmd->gpuDescriptorSets = _curGPUDescriptorSets;
if (_curGPUPipelineState) {
ccstd::vector<uint32_t> &dynamicOffsetOffsets = _curGPUPipelineState->gpuPipelineLayout->dynamicOffsetOffsets;
cmd->dynamicOffsets.resize(_curGPUPipelineState->gpuPipelineLayout->dynamicOffsetCount);
for (size_t i = 0U; i < _curDynamicOffsets.size(); i++) {
size_t count = dynamicOffsetOffsets[i + 1] - dynamicOffsetOffsets[i];
// CC_ASSERT(_curDynamicOffsets[i].size() >= count);
count = std::min(count, _curDynamicOffsets[i].size());
if (count) memcpy(&cmd->dynamicOffsets[dynamicOffsetOffsets[i]], _curDynamicOffsets[i].data(), count * sizeof(uint32_t));
}
}
cmd->dynamicStates = _curDynamicStates;
_curCmdPackage->bindStatesCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::BIND_STATES);
_isStateInvalid = false;
}
void GLES3CommandBuffer::dispatch(const DispatchInfo &info) {
if (_isStateInvalid) {
bindStates();
}
GLES3CmdDispatch *cmd = _cmdAllocator->dispatchCmdPool.alloc();
if (info.indirectBuffer) {
cmd->dispatchInfo.indirectBuffer = static_cast<GLES3Buffer *>(info.indirectBuffer)->gpuBuffer();
cmd->dispatchInfo.indirectOffset = info.indirectOffset;
} else {
cmd->dispatchInfo.groupCountX = info.groupCountX;
cmd->dispatchInfo.groupCountY = info.groupCountY;
cmd->dispatchInfo.groupCountZ = info.groupCountZ;
}
_curCmdPackage->dispatchCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::DISPATCH);
}
void GLES3CommandBuffer::pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const * /*bufferBarriers*/, const Buffer *const * /*buffers*/, uint32_t /*bufferCount*/, const TextureBarrier *const * /*textureBarriers*/, const Texture *const * /*textures*/, uint32_t /*textureBarrierCount*/) {
if (!barrier) return;
const auto *gpuBarrier = static_cast<const GLES3GeneralBarrier *>(barrier)->gpuBarrier();
GLES3CmdBarrier *cmd = _cmdAllocator->barrierCmdPool.alloc();
cmd->barriers = gpuBarrier->glBarriers;
cmd->barriersByRegion = gpuBarrier->glBarriersByRegion;
_curCmdPackage->barrierCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::BARRIER);
}
void GLES3CommandBuffer::beginQuery(QueryPool *queryPool, uint32_t id) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
GLES3CmdQuery *cmd = _cmdAllocator->queryCmdPool.alloc();
cmd->queryPool = gles3QueryPool;
cmd->type = GLES3QueryType::BEGIN;
cmd->id = id;
_curCmdPackage->queryCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::QUERY);
}
void GLES3CommandBuffer::endQuery(QueryPool *queryPool, uint32_t id) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
GLES3CmdQuery *cmd = _cmdAllocator->queryCmdPool.alloc();
cmd->queryPool = gles3QueryPool;
cmd->type = GLES3QueryType::END;
cmd->id = id;
_curCmdPackage->queryCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::QUERY);
}
void GLES3CommandBuffer::resetQueryPool(QueryPool *queryPool) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
GLES3CmdQuery *cmd = _cmdAllocator->queryCmdPool.alloc();
cmd->queryPool = gles3QueryPool;
cmd->type = GLES3QueryType::RESET;
cmd->id = 0;
_curCmdPackage->queryCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::QUERY);
}
void GLES3CommandBuffer::getQueryPoolResults(QueryPool *queryPool) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
GLES3CmdQuery *cmd = _cmdAllocator->queryCmdPool.alloc();
cmd->queryPool = gles3QueryPool;
cmd->type = GLES3QueryType::GET_RESULTS;
cmd->id = 0;
_curCmdPackage->queryCmds.push(cmd);
_curCmdPackage->cmds.push(GLESCmdType::QUERY);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,104 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "base/std/container/queue.h"
#include "gfx-base/GFXCommandBuffer.h"
namespace cc {
namespace gfx {
class GLES3GPUCommandAllocator;
struct GLES3CmdPackage;
struct GLES3GPUPipelineState;
struct GLES3GPUInputAssembler;
struct GLES3GPUDescriptorSet;
struct GLES3GPURenderPass;
class CC_GLES3_API GLES3CommandBuffer : public CommandBuffer {
public:
GLES3CommandBuffer();
~GLES3CommandBuffer() override;
void begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *frameBuffer) override;
void end() override;
void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) override;
void endRenderPass() override;
void insertMarker(const MarkerInfo &marker) override;
void beginMarker(const MarkerInfo &marker) override;
void endMarker() override;
void bindPipelineState(PipelineState *pso) override;
void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) override;
void bindInputAssembler(InputAssembler *ia) override;
void setViewport(const Viewport &vp) override;
void setScissor(const Rect &rect) override;
void setLineWidth(float width) override;
void setDepthBias(float constant, float clamp, float slope) override;
void setBlendConstants(const Color &constants) override;
void setDepthBound(float minBounds, float maxBounds) override;
void setStencilWriteMask(StencilFace face, uint32_t mask) override;
void setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) override;
void nextSubpass() override;
void draw(const DrawInfo &info) override;
void updateBuffer(Buffer *buff, const void *data, uint32_t size) override;
void copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) override;
void blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) override;
void copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
void resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
void execute(CommandBuffer *const *cmdBuffs, uint32_t count) override;
void dispatch(const DispatchInfo &info) override;
void pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const * /*buffers*/, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const * /*textures*/, uint32_t textureBarrierCount) override;
void beginQuery(QueryPool *queryPool, uint32_t id) override;
void endQuery(QueryPool *queryPool, uint32_t id) override;
void resetQueryPool(QueryPool *queryPool) override;
protected:
friend class GLES3Queue;
friend class GLES3Device;
virtual void getQueryPoolResults(QueryPool *query);
void doInit(const CommandBufferInfo &info) override;
void doDestroy() override;
virtual void bindStates();
GLES3GPUCommandAllocator *_cmdAllocator = nullptr;
GLES3CmdPackage *_curCmdPackage = nullptr;
ccstd::queue<GLES3CmdPackage *> _pendingPackages, _freePackages;
uint32_t _curSubpassIdx = 0U;
GLES3GPUPipelineState *_curGPUPipelineState = nullptr;
GLES3GPUInputAssembler *_curGPUInputAssember = nullptr;
ccstd::vector<GLES3GPUDescriptorSet *> _curGPUDescriptorSets;
ccstd::vector<ccstd::vector<uint32_t>> _curDynamicOffsets;
DynamicStates _curDynamicStates;
bool _isStateInvalid = false;
};
} // namespace gfx
} // namespace cc

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3GPUObjects.h"
namespace cc {
namespace gfx {
class GLES3Device;
class GLES3QueryPool;
class GLES3CmdBeginRenderPass final : public GLESCmd {
public:
GLES3GPURenderPass *gpuRenderPass = nullptr;
GLES3GPUFramebuffer *gpuFBO = nullptr;
Rect renderArea;
Color clearColors[MAX_ATTACHMENTS];
float clearDepth = 1.0F;
uint32_t clearStencil = 0U;
uint32_t subpassIdx = 0U;
GLES3CmdBeginRenderPass() : GLESCmd(GLESCmdType::BEGIN_RENDER_PASS) {}
void clear() override {
gpuRenderPass = nullptr;
gpuFBO = nullptr;
}
};
class GLES3CmdBindStates final : public GLESCmd {
public:
GLES3GPUPipelineState *gpuPipelineState = nullptr;
GLES3GPUInputAssembler *gpuInputAssembler = nullptr;
ccstd::vector<GLES3GPUDescriptorSet *> gpuDescriptorSets;
ccstd::vector<uint32_t> dynamicOffsets;
DynamicStates dynamicStates;
GLES3CmdBindStates() : GLESCmd(GLESCmdType::BIND_STATES) {}
void clear() override {
gpuPipelineState = nullptr;
gpuInputAssembler = nullptr;
gpuDescriptorSets.clear();
dynamicOffsets.clear();
}
};
class GLES3CmdDraw final : public GLESCmd {
public:
DrawInfo drawInfo;
GLES3CmdDraw() : GLESCmd(GLESCmdType::DRAW) {}
void clear() override {}
};
class GLES3CmdDispatch final : public GLESCmd {
public:
GLES3GPUDispatchInfo dispatchInfo;
GLES3CmdDispatch() : GLESCmd(GLESCmdType::DISPATCH) {}
void clear() override {
dispatchInfo.indirectBuffer = nullptr;
dispatchInfo.indirectOffset = 0;
}
};
class GLES3CmdBarrier final : public GLESCmd {
public:
GLbitfield barriers = 0U;
GLbitfield barriersByRegion = 0U;
GLES3CmdBarrier() : GLESCmd(GLESCmdType::BARRIER) {}
void clear() override {
barriers = 0U;
barriersByRegion = 0U;
}
};
class GLES3CmdUpdateBuffer final : public GLESCmd {
public:
GLES3GPUBuffer *gpuBuffer = nullptr;
const uint8_t *buffer = nullptr;
uint32_t size = 0;
uint32_t offset = 0;
GLES3CmdUpdateBuffer() : GLESCmd(GLESCmdType::UPDATE_BUFFER) {}
void clear() override {
gpuBuffer = nullptr;
buffer = nullptr;
}
};
class GLES3CmdCopyBufferToTexture final : public GLESCmd {
public:
GLES3GPUTexture *gpuTexture = nullptr;
const BufferTextureCopy *regions = nullptr;
uint32_t count = 0U;
const uint8_t *const *buffers = nullptr;
GLES3CmdCopyBufferToTexture() : GLESCmd(GLESCmdType::COPY_BUFFER_TO_TEXTURE) {}
void clear() override {
gpuTexture = nullptr;
regions = nullptr;
count = 0U;
buffers = nullptr;
}
};
class GLES3CmdBlitTexture final : public GLESCmd {
public:
GLES3GPUTextureView *gpuTextureSrcView = nullptr;
GLES3GPUTextureView *gpuTextureDstView = nullptr;
const TextureBlit *regions = nullptr;
uint32_t count = 0U;
Filter filter = Filter::POINT;
GLES3CmdBlitTexture() : GLESCmd(GLESCmdType::BLIT_TEXTURE) {}
void clear() override {
gpuTextureSrcView = nullptr;
gpuTextureDstView = nullptr;
regions = nullptr;
count = 0U;
}
};
enum class GLES3QueryType : uint8_t {
BEGIN,
END,
RESET,
GET_RESULTS,
};
class GLES3CmdQuery final : public GLESCmd {
public:
GLES3QueryPool *queryPool = nullptr;
GLES3QueryType type = GLES3QueryType::BEGIN;
uint32_t id = 0U;
GLES3CmdQuery() : GLESCmd(GLESCmdType::QUERY) {}
void clear() override {
queryPool = nullptr;
type = GLES3QueryType::BEGIN;
id = 0U;
}
};
struct GLES3CmdPackage {
CachedArray<GLESCmdType> cmds;
CachedArray<GLES3CmdBeginRenderPass *> beginRenderPassCmds;
CachedArray<GLES3CmdBindStates *> bindStatesCmds;
CachedArray<GLES3CmdDraw *> drawCmds;
CachedArray<GLES3CmdDispatch *> dispatchCmds;
CachedArray<GLES3CmdBarrier *> barrierCmds;
CachedArray<GLES3CmdUpdateBuffer *> updateBufferCmds;
CachedArray<GLES3CmdCopyBufferToTexture *> copyBufferToTextureCmds;
CachedArray<GLES3CmdBlitTexture *> blitTextureCmds;
CachedArray<GLES3CmdQuery *> queryCmds;
};
class GLES3GPUCommandAllocator final {
public:
CommandPool<GLES3CmdBeginRenderPass> beginRenderPassCmdPool;
CommandPool<GLES3CmdBindStates> bindStatesCmdPool;
CommandPool<GLES3CmdDraw> drawCmdPool;
CommandPool<GLES3CmdDispatch> dispatchCmdPool;
CommandPool<GLES3CmdBarrier> barrierCmdPool;
CommandPool<GLES3CmdUpdateBuffer> updateBufferCmdPool;
CommandPool<GLES3CmdCopyBufferToTexture> copyBufferToTextureCmdPool;
CommandPool<GLES3CmdBlitTexture> blitTextureCmdPool;
CommandPool<GLES3CmdQuery> queryCmdPool;
void clearCmds(GLES3CmdPackage *cmdPackage) {
if (cmdPackage->beginRenderPassCmds.size()) {
beginRenderPassCmdPool.freeCmds(cmdPackage->beginRenderPassCmds);
}
if (cmdPackage->bindStatesCmds.size()) {
bindStatesCmdPool.freeCmds(cmdPackage->bindStatesCmds);
}
if (cmdPackage->drawCmds.size()) {
drawCmdPool.freeCmds(cmdPackage->drawCmds);
}
if (cmdPackage->dispatchCmds.size()) {
dispatchCmdPool.freeCmds(cmdPackage->dispatchCmds);
}
if (cmdPackage->barrierCmds.size()) {
barrierCmdPool.freeCmds(cmdPackage->barrierCmds);
}
if (cmdPackage->updateBufferCmds.size()) {
updateBufferCmdPool.freeCmds(cmdPackage->updateBufferCmds);
}
if (cmdPackage->copyBufferToTextureCmds.size()) {
copyBufferToTextureCmdPool.freeCmds(cmdPackage->copyBufferToTextureCmds);
}
if (cmdPackage->blitTextureCmds.size()) {
blitTextureCmdPool.freeCmds(cmdPackage->blitTextureCmds);
}
if (cmdPackage->queryCmds.size()) {
queryCmdPool.freeCmds(cmdPackage->queryCmds);
}
cmdPackage->cmds.clear();
}
inline void reset() {
beginRenderPassCmdPool.release();
bindStatesCmdPool.release();
drawCmdPool.release();
dispatchCmdPool.release();
barrierCmdPool.release();
updateBufferCmdPool.release();
copyBufferToTextureCmdPool.release();
blitTextureCmdPool.release();
}
};
void cmdFuncGLES3CreateBuffer(GLES3Device *device, GLES3GPUBuffer *gpuBuffer);
void cmdFuncGLES3DestroyBuffer(GLES3Device *device, GLES3GPUBuffer *gpuBuffer);
void cmdFuncGLES3ResizeBuffer(GLES3Device *device, GLES3GPUBuffer *gpuBuffer);
void cmdFuncGLES3CreateTexture(GLES3Device *device, GLES3GPUTexture *gpuTexture);
void cmdFuncGLES3DestroyTexture(GLES3Device *device, GLES3GPUTexture *gpuTexture);
void cmdFuncGLES3ResizeTexture(GLES3Device *device, GLES3GPUTexture *gpuTexture);
void cmdFuncGLES3CreateTextureView(GLES3Device *device, GLES3GPUTextureView *gpuTextureView);
void cmdFuncGLES3CreateShader(GLES3Device *device, GLES3GPUShader *gpuShader, GLES3GPUPipelineLayout *pipelineLayout);
void cmdFuncGLES3DestroyShader(GLES3Device *device, GLES3GPUShader *gpuShader);
void cmdFuncGLES3CreateRenderPass(GLES3Device *device, GLES3GPURenderPass *gpuRenderPass);
void cmdFuncGLES3DestroyRenderPass(GLES3Device *device, GLES3GPURenderPass *gpuRenderPass);
void cmdFuncGLES3CreateInputAssembler(GLES3Device *device, GLES3GPUInputAssembler *gpuInputAssembler);
void cmdFuncGLES3DestroyInputAssembler(GLES3Device *device, GLES3GPUInputAssembler *gpuInputAssembler);
void cmdFuncGLES3CreateFramebuffer(GLES3Device *device, GLES3GPUFramebuffer *gpuFBO);
void cmdFuncGLES3DestroyFramebuffer(GLES3Device *device, GLES3GPUFramebuffer *gpuFBO);
void cmdFuncGLES3CreateGeneralBarrier(GLES3Device *device, GLES3GPUGeneralBarrier *barrier);
void cmdFuncGLES3CreateQueryPool(GLES3Device *device, GLES3GPUQueryPool *gpuQueryPool);
void cmdFuncGLES3DestroyQueryPool(GLES3Device *device, GLES3GPUQueryPool *gpuQueryPool);
void cmdFuncGLES3PrepareSamplerInfo(GLES3Device *device, GLES3GPUSampler *gpuSampler);
void completeBarrier(GLES3GPUGeneralBarrier *barrier);
void cmdFuncGLES3Query(GLES3Device *device, GLES3QueryPool *query, GLES3QueryType type, uint32_t id);
void cmdFuncGLES3BeginRenderPass(GLES3Device *device,
GLES3GPURenderPass *gpuRenderPass = nullptr,
GLES3GPUFramebuffer *gpuFramebuffer = nullptr,
const Rect *renderArea = nullptr,
const Color *clearColors = nullptr,
float clearDepth = 1.F,
uint32_t clearStencil = 0);
void cmdFuncGLES3EndRenderPass(GLES3Device *device);
void cmdFuncGLES3BindState(GLES3Device *device,
GLES3GPUPipelineState *gpuPipelineState,
GLES3GPUInputAssembler *gpuInputAssembler,
const GLES3GPUDescriptorSet *const *gpuDescriptorSets,
const uint32_t *dynamicOffsets = nullptr,
const DynamicStates *dynamicStates = nullptr);
void cmdFuncGLES3Draw(GLES3Device *device, const DrawInfo &drawInfo);
void cmdFuncGLES3UpdateBuffer(GLES3Device *device,
GLES3GPUBuffer *gpuBuffer,
const void *buffer,
uint32_t offset,
uint32_t size);
void cmdFuncGLES3CopyBuffersToTexture(GLES3Device *device,
const uint8_t *const *buffers,
GLES3GPUTexture *gpuTexture,
const BufferTextureCopy *regions,
uint32_t count);
void cmdFuncGLES3CopyTextureToBuffers(GLES3Device *device,
GLES3GPUTextureView *gpuTextureView,
uint8_t *const *buffers,
const BufferTextureCopy *regions,
uint32_t count);
void cmdFuncGLES3BlitTexture(GLES3Device *device,
GLES3GPUTextureView *gpuTextureSrcView,
GLES3GPUTextureView *gpuTextureDstView,
const TextureBlit *regions,
uint32_t count,
Filter filter);
void cmdFuncGLES3ExecuteCmds(GLES3Device *device, GLES3CmdPackage *cmdPackage);
void cmdFuncGLES3Dispatch(GLES3Device *device, const GLES3GPUDispatchInfo &info);
void cmdFuncGLES3MemoryBarrier(GLES3Device *device, GLbitfield barriers, GLbitfield barriersByRegion);
void cmdFuncGLES3InsertMarker(GLES3Device *device, GLsizei length, const char *marker);
void cmdFuncGLES3PushGroupMarker(GLES3Device *device, GLsizei length, const char *marker);
void cmdFuncGLES3PopGroupMarker(GLES3Device *device);
GLint cmdFuncGLES3GetMaxSampleCount(const GLES3Device *device, Format format, TextureUsage usage, TextureFlags flags);
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,108 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Buffer.h"
#include "GLES3Commands.h"
#include "GLES3DescriptorSet.h"
#include "GLES3DescriptorSetLayout.h"
#include "GLES3Device.h"
#include "GLES3Texture.h"
#include "gfx-gles3/GLES3GPUObjects.h"
#include "states/GLES3Sampler.h"
namespace cc {
namespace gfx {
GLES3DescriptorSet::GLES3DescriptorSet() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3DescriptorSet::~GLES3DescriptorSet() {
destroy();
}
void GLES3DescriptorSet::doInit(const DescriptorSetInfo & /*info*/) {
const GLES3GPUDescriptorSetLayout *gpuDescriptorSetLayout = static_cast<const GLES3DescriptorSetLayout *>(_layout)->gpuDescriptorSetLayout();
const size_t descriptorCount = gpuDescriptorSetLayout->descriptorCount;
const size_t bindingCount = gpuDescriptorSetLayout->bindings.size();
_gpuDescriptorSet = ccnew GLES3GPUDescriptorSet;
_gpuDescriptorSet->gpuDescriptors.resize(descriptorCount);
for (size_t i = 0U, k = 0U; i < bindingCount; i++) {
const DescriptorSetLayoutBinding &binding = gpuDescriptorSetLayout->bindings[i];
for (uint32_t j = 0; j < binding.count; j++, k++) {
_gpuDescriptorSet->gpuDescriptors[k].type = binding.descriptorType;
}
}
_gpuDescriptorSet->descriptorIndices = &gpuDescriptorSetLayout->descriptorIndices;
}
void GLES3DescriptorSet::doDestroy() {
CC_SAFE_DELETE(_gpuDescriptorSet);
}
void GLES3DescriptorSet::update() {
if (_isDirty && _gpuDescriptorSet) {
auto &descriptors = _gpuDescriptorSet->gpuDescriptors;
for (size_t i = 0; i < descriptors.size(); i++) {
if (hasAnyFlags(descriptors[i].type, DESCRIPTOR_BUFFER_TYPE)) {
if (_buffers[i].ptr) {
descriptors[i].gpuBuffer = static_cast<GLES3Buffer *>(_buffers[i].ptr)->gpuBuffer();
}
} else if (hasAnyFlags(descriptors[i].type, DESCRIPTOR_TEXTURE_TYPE)) {
if (_samplers[i].ptr) {
descriptors[i].gpuSampler = static_cast<GLES3Sampler *>(_samplers[i].ptr)->gpuSampler();
}
if (_textures[i].ptr) {
_gpuDescriptorSet->gpuDescriptors[i].gpuTextureView = static_cast<GLES3Texture *>(_textures[i].ptr)->gpuTextureView();
// work around for sample depth stencil texture, delete when rdg support set sampler.
const FormatInfo &info = GFX_FORMAT_INFOS[toNumber(
_textures[i].ptr->getFormat())];
if (info.hasDepth || info.hasStencil) {
gfx::SamplerInfo samplerInfo = {};
samplerInfo.minFilter = gfx::Filter::POINT;
samplerInfo.magFilter = gfx::Filter::POINT;
descriptors[i].gpuSampler = static_cast<GLES3Sampler *>(Device::getInstance()->getSampler(
samplerInfo))
->gpuSampler();
}
}
}
}
_isDirty = false;
}
}
void GLES3DescriptorSet::forceUpdate() {
_isDirty = true;
update();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,53 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXDescriptorSet.h"
namespace cc {
namespace gfx {
struct GLES3GPUDescriptorSet;
class CC_GLES3_API GLES3DescriptorSet final : public DescriptorSet {
public:
GLES3DescriptorSet();
~GLES3DescriptorSet() override;
void update() override;
void forceUpdate() override;
inline GLES3GPUDescriptorSet *gpuDescriptorSet() const { return _gpuDescriptorSet; }
protected:
void doInit(const DescriptorSetInfo &info) override;
void doDestroy() override;
GLES3GPUDescriptorSet *_gpuDescriptorSet = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,72 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3DescriptorSetLayout.h"
#include "states/GLES3Sampler.h"
namespace cc {
namespace gfx {
GLES3DescriptorSetLayout::GLES3DescriptorSetLayout() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3DescriptorSetLayout::~GLES3DescriptorSetLayout() {
destroy();
}
void GLES3DescriptorSetLayout::doInit(const DescriptorSetLayoutInfo & /*info*/) {
_gpuDescriptorSetLayout = ccnew GLES3GPUDescriptorSetLayout;
_gpuDescriptorSetLayout->descriptorCount = _descriptorCount;
_gpuDescriptorSetLayout->bindingIndices = _bindingIndices;
_gpuDescriptorSetLayout->descriptorIndices = _descriptorIndices;
_gpuDescriptorSetLayout->bindings = _bindings;
auto &hash = _gpuDescriptorSetLayout->hash;
for (auto &binding : _bindings) {
if (hasAnyFlags(binding.descriptorType, DESCRIPTOR_DYNAMIC_TYPE)) {
for (uint32_t j = 0U; j < binding.count; j++) {
_gpuDescriptorSetLayout->dynamicBindings.push_back(binding.binding);
}
}
ccstd::hash_combine(hash, binding.binding);
ccstd::hash_combine(hash, binding.descriptorType);
ccstd::hash_combine(hash, binding.count);
ccstd::hash_combine(hash, binding.stageFlags);
for (auto &sampler : binding.immutableSamplers) {
ccstd::hash_combine(hash, sampler->getHash());
}
}
}
void GLES3DescriptorSetLayout::doDestroy() {
CC_SAFE_DELETE(_gpuDescriptorSetLayout);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXDescriptorSetLayout.h"
namespace cc {
namespace gfx {
struct GLES3GPUDescriptorSetLayout;
class CC_GLES3_API GLES3DescriptorSetLayout final : public DescriptorSetLayout {
public:
GLES3DescriptorSetLayout();
~GLES3DescriptorSetLayout() override;
inline GLES3GPUDescriptorSetLayout *gpuDescriptorSetLayout() const { return _gpuDescriptorSetLayout; }
protected:
void doInit(const DescriptorSetLayoutInfo &info) override;
void doDestroy() override;
GLES3GPUDescriptorSetLayout *_gpuDescriptorSetLayout = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,625 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Buffer.h"
#include "GLES3CommandBuffer.h"
#include "GLES3Commands.h"
#include "GLES3DescriptorSet.h"
#include "GLES3DescriptorSetLayout.h"
#include "GLES3Device.h"
#include "GLES3Framebuffer.h"
#include "GLES3GPUObjects.h"
#include "GLES3InputAssembler.h"
#include "GLES3PipelineCache.h"
#include "GLES3PipelineLayout.h"
#include "GLES3PipelineState.h"
#include "GLES3PrimaryCommandBuffer.h"
#include "GLES3QueryPool.h"
#include "GLES3Queue.h"
#include "GLES3RenderPass.h"
#include "GLES3Shader.h"
#include "GLES3Swapchain.h"
#include "GLES3Texture.h"
#include "application/ApplicationManager.h"
#include "platform/interfaces/modules/IXRInterface.h"
#include "profiler/Profiler.h"
#include "states/GLES3GeneralBarrier.h"
#include "states/GLES3Sampler.h"
// when capturing GLES commands (RENDERDOC_HOOK_EGL=1, default value)
// renderdoc doesn't support this extension during replay
#define ALLOW_MULTISAMPLED_RENDER_TO_TEXTURE_ON_DESKTOP 0
namespace cc {
namespace gfx {
GLES3Device *GLES3Device::instance = nullptr;
GLES3Device *GLES3Device::getInstance() {
return GLES3Device::instance;
}
GLES3Device::GLES3Device() {
_api = API::GLES3;
_deviceName = "GLES3";
GLES3Device::instance = this;
}
GLES3Device::~GLES3Device() {
GLES3Device::instance = nullptr;
}
bool GLES3Device::doInit(const DeviceInfo & /*info*/) {
_xr = CC_GET_XR_INTERFACE();
if (_xr) _xr->preGFXDeviceInitialize(_api);
_gpuContext = ccnew GLES3GPUContext;
_gpuStateCache = ccnew GLES3GPUStateCache;
_gpuFramebufferHub = ccnew GLES3GPUFramebufferHub;
_gpuConstantRegistry = ccnew GLES3GPUConstantRegistry;
_gpuFramebufferCacheMap = ccnew GLES3GPUFramebufferCacheMap(_gpuStateCache);
if (!_gpuContext->initialize(_gpuStateCache, _gpuConstantRegistry)) {
destroy();
return false;
};
_bindingMappings.blockOffsets.resize(_bindingMappingInfo.setIndices.size());
_bindingMappings.samplerTextureOffsets.resize(_bindingMappingInfo.setIndices.size());
for (size_t i = 0; i < _bindingMappingInfo.setIndices.size(); ++i) {
uint32_t curSet{_bindingMappingInfo.setIndices[i]};
uint32_t prevSet{i ? _bindingMappingInfo.setIndices[i - 1] : curSet};
// accumulate the per set offset according to the specified capacity
_bindingMappings.blockOffsets[curSet] = i ? static_cast<int32_t>(_bindingMappingInfo.maxBlockCounts[prevSet]) + _bindingMappings.blockOffsets[prevSet] : 0;
_bindingMappings.samplerTextureOffsets[curSet] = i ? static_cast<int32_t>(_bindingMappingInfo.maxSamplerTextureCounts[prevSet]) + _bindingMappings.samplerTextureOffsets[prevSet] : 0;
}
for (uint32_t curSet : _bindingMappingInfo.setIndices) {
// textures always come after UBOs
_bindingMappings.samplerTextureOffsets[curSet] -= static_cast<int32_t>(_bindingMappingInfo.maxBlockCounts[curSet]);
}
_bindingMappings.flexibleSet = _bindingMappingInfo.setIndices.back();
ccstd::string extStr = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
_extensions = StringUtil::split(extStr, " ");
initFormatFeature();
_multithreadedCommandRecording = false;
_features[toNumber(Feature::INSTANCED_ARRAYS)] = true;
_features[toNumber(Feature::MULTIPLE_RENDER_TARGETS)] = true;
_features[toNumber(Feature::BLEND_MINMAX)] = true;
_features[toNumber(Feature::ELEMENT_INDEX_UINT)] = true;
_features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = false;
if (_gpuConstantRegistry->glMinorVersion) {
_features[toNumber(Feature::COMPUTE_SHADER)] = true;
}
ccstd::string fbfLevelStr = "NONE";
// PVRVFrame has issues on their support
if (checkExtension("framebuffer_fetch")) {
ccstd::string nonCoherent = "framebuffer_fetch_non";
auto it = std::find_if(_extensions.begin(), _extensions.end(), [&nonCoherent](auto &ext) {
return ext.find(nonCoherent) != ccstd::string::npos;
});
if (it != _extensions.end()) {
if (*it == CC_TOSTR(GL_EXT_shader_framebuffer_fetch_non_coherent)) {
_gpuConstantRegistry->mFBF = FBFSupportLevel::NON_COHERENT_EXT;
_features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = true;
fbfLevelStr = "NON_COHERENT_EXT";
} else if (*it == CC_TOSTR(GL_QCOM_shader_framebuffer_fetch_noncoherent)) {
_gpuConstantRegistry->mFBF = FBFSupportLevel::NON_COHERENT_QCOM;
fbfLevelStr = "NON_COHERENT_QCOM";
_features[toNumber(Feature::RASTERIZATION_ORDER_NOCOHERENT)] = true;
GL_CHECK(glEnable(GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM));
}
} else if (checkExtension(CC_TOSTR(GL_EXT_shader_framebuffer_fetch))) {
// we only care about EXT_shader_framebuffer_fetch, the ARM version does not support MRT
_gpuConstantRegistry->mFBF = FBFSupportLevel::COHERENT;
fbfLevelStr = "COHERENT";
}
_features[toNumber(Feature::INPUT_ATTACHMENT_BENEFIT)] = _gpuConstantRegistry->mFBF != FBFSupportLevel::NONE;
_features[toNumber(Feature::SUBPASS_COLOR_INPUT)] = true;
}
if (checkExtension(CC_TOSTR(GL_EXT_debug_marker))) {
_gpuConstantRegistry->debugMarker = true;
}
if (checkExtension(CC_TOSTR(ARM_shader_framebuffer_fetch_depth_stencil))) {
_features[toNumber(Feature::SUBPASS_DEPTH_STENCIL_INPUT)] = true;
fbfLevelStr += "_DEPTH_STENCIL";
}
ccstd::string msaaLevelStr = "NONE";
#if CC_PLATFORM != CC_PLATFORM_WINDOWS || ALLOW_MULTISAMPLED_RENDER_TO_TEXTURE_ON_DESKTOP
if (checkExtension("multisampled_render_to_texture")) {
msaaLevelStr = "MSRT1";
if (checkExtension("multisampled_render_to_texture2")) {
_gpuConstantRegistry->mMSRT = MSRTSupportLevel::LEVEL2;
msaaLevelStr = "MSRT2";
} else {
_gpuConstantRegistry->mMSRT = MSRTSupportLevel::LEVEL1;
}
}
#endif
_features[toNumber(Feature::MULTI_SAMPLE_RESOLVE_DEPTH_STENCIL)] = true;
ccstd::string compressedFmts;
if (getFormatFeatures(Format::ETC_RGB8) != FormatFeature::NONE) {
compressedFmts += "etc1 ";
}
compressedFmts += "etc2 ";
if (getFormatFeatures(Format::PVRTC_RGB2) != FormatFeature::NONE) {
compressedFmts += "pvrtc ";
}
if (getFormatFeatures(Format::ASTC_RGBA_4X4) != FormatFeature::NONE) {
compressedFmts += "astc ";
}
_renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
_vendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
_version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, reinterpret_cast<GLint *>(&_caps.maxVertexAttributes));
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, reinterpret_cast<GLint *>(&_caps.maxVertexUniformVectors));
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, reinterpret_cast<GLint *>(&_caps.maxFragmentUniformVectors));
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, reinterpret_cast<GLint *>(&_caps.maxUniformBufferBindings));
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, reinterpret_cast<GLint *>(&_caps.maxUniformBlockSize));
glGetIntegerv(GL_MAX_DRAW_BUFFERS, reinterpret_cast<GLint *>(&_caps.maxColorRenderTargets));
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, reinterpret_cast<GLint *>(&_caps.maxTextureUnits));
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, reinterpret_cast<GLint *>(&_caps.maxVertexTextureUnits));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, reinterpret_cast<GLint *>(&_caps.maxTextureSize));
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, reinterpret_cast<GLint *>(&_caps.maxCubeMapTextureSize));
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast<GLint *>(&_caps.uboOffsetAlignment));
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, reinterpret_cast<GLint *>(&_caps.maxArrayTextureLayers));
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, reinterpret_cast<GLint *>(&_caps.max3DTextureSize));
if (_gpuConstantRegistry->glMinorVersion) {
glGetIntegerv(GL_MAX_IMAGE_UNITS, reinterpret_cast<GLint *>(&_caps.maxImageUnits));
glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, reinterpret_cast<GLint *>(&_caps.maxShaderStorageBlockSize));
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, reinterpret_cast<GLint *>(&_caps.maxShaderStorageBufferBindings));
glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, reinterpret_cast<GLint *>(&_caps.maxComputeSharedMemorySize));
glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupInvocations));
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupSize.x));
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupSize.y));
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupSize.z));
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupCount.x));
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupCount.y));
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, reinterpret_cast<GLint *>(&_caps.maxComputeWorkGroupCount.z));
}
if (checkExtension("occlusion_query_boolean")) {
_caps.supportQuery = true;
}
QueueInfo queueInfo;
queueInfo.type = QueueType::GRAPHICS;
_queue = createQueue(queueInfo);
QueryPoolInfo queryPoolInfo{QueryType::OCCLUSION, DEFAULT_MAX_QUERY_OBJECTS, true};
_queryPool = createQueryPool(queryPoolInfo);
CommandBufferInfo cmdBuffInfo;
cmdBuffInfo.type = CommandBufferType::PRIMARY;
cmdBuffInfo.queue = _queue;
_cmdBuff = createCommandBuffer(cmdBuffInfo);
_gpuStateCache->initialize(_caps.maxTextureUnits, _caps.maxImageUnits, _caps.maxUniformBufferBindings, _caps.maxShaderStorageBufferBindings, _caps.maxVertexAttributes);
#if CC_USE_PIPELINE_CACHE
_pipelineCache = std::make_unique<GLES3PipelineCache>();
_pipelineCache->init();
#endif
CC_LOG_INFO("GLES3 device initialized.");
CC_LOG_INFO("RENDERER: %s", _renderer.c_str());
CC_LOG_INFO("VENDOR: %s", _vendor.c_str());
CC_LOG_INFO("VERSION: %s", _version.c_str());
CC_LOG_INFO("COMPRESSED_FORMATS: %s", compressedFmts.c_str());
CC_LOG_INFO("FRAMEBUFFER_FETCH: %s", fbfLevelStr.c_str());
CC_LOG_INFO("MULTI_SAMPLE_RENDER_TO_TEXTURE: %s", msaaLevelStr.c_str());
if (_xr) {
_xr->initializeGLESData(pfnGLES3wLoadProc(), GLES3Device::getInstance()->context());
_xr->postGFXDeviceInitialize(_api);
}
return true;
}
void GLES3Device::doDestroy() {
CC_SAFE_DELETE(_gpuFramebufferCacheMap)
CC_SAFE_DELETE(_gpuConstantRegistry)
CC_SAFE_DELETE(_gpuFramebufferHub)
CC_SAFE_DELETE(_gpuStateCache)
CC_ASSERT(!_memoryStatus.bufferSize); // Buffer memory leaked
CC_ASSERT(!_memoryStatus.textureSize); // Texture memory leaked
CC_SAFE_DESTROY_AND_DELETE(_cmdBuff)
CC_SAFE_DESTROY_AND_DELETE(_queryPool)
CC_SAFE_DESTROY_AND_DELETE(_queue)
CC_SAFE_DESTROY_AND_DELETE(_gpuContext)
_pipelineCache.reset();
}
void GLES3Device::acquire(Swapchain *const *swapchains, uint32_t count) {
_gpuContext->makeCurrent();
if (_onAcquire) _onAcquire->execute();
_swapchains.clear();
if (_xr) {
GLuint xrFramebuffer = 0;
#if XR_OEM_HUAWEIVR
stateCache()->glTextures[stateCache()->texUint] = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, reinterpret_cast<GLint *>(&xrFramebuffer));
stateCache()->glDrawFramebuffer = xrFramebuffer;
#else
xr::XRSwapchain xrSwapchain = _xr->doGFXDeviceAcquire(_api);
xrFramebuffer = xrSwapchain.glDrawFramebuffer;
#endif
for (uint32_t i = 0; i < count; ++i) {
GL_CHECK(_xr->attachGLESFramebufferTexture2D(););
static_cast<GLES3Swapchain *>(swapchains[i])->gpuSwapchain()->glFramebuffer = xrFramebuffer;
_swapchains.push_back(static_cast<GLES3Swapchain *>(swapchains[i])->gpuSwapchain());
}
return;
}
for (uint32_t i = 0; i < count; ++i) {
_swapchains.push_back(static_cast<GLES3Swapchain *>(swapchains[i])->gpuSwapchain());
}
}
void GLES3Device::present() {
CC_PROFILE(GLES3DevicePresent);
auto *queue = static_cast<GLES3Queue *>(_queue);
_numDrawCalls = queue->_numDrawCalls;
_numInstances = queue->_numInstances;
_numTriangles = queue->_numTriangles;
bool isGFXDeviceNeedsPresent = _xr ? _xr->isGFXDeviceNeedsPresent(_api) : true;
for (auto *swapchain : _swapchains) {
if (isGFXDeviceNeedsPresent) _gpuContext->present(swapchain);
}
if (_xr) _xr->postGFXDevicePresent(_api);
// Clear queue stats
queue->_numDrawCalls = 0;
queue->_numInstances = 0;
queue->_numTriangles = 0;
}
void GLES3Device::bindContext(bool bound) {
_gpuContext->bindContext(bound);
}
void GLES3Device::initFormatFeature() {
_textureExclusive.fill(true);
FormatFeature tempFeature = {};
// builtin
tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE;
_formatFeatures[toNumber(Format::R8)] = tempFeature;
_formatFeatures[toNumber(Format::RG8)] = tempFeature;
_formatFeatures[toNumber(Format::RGB8)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA8)] = tempFeature;
tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE;
_formatFeatures[toNumber(Format::R8SN)] = tempFeature;
_formatFeatures[toNumber(Format::RG8SN)] = tempFeature;
_formatFeatures[toNumber(Format::RGB8SN)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA8SN)] = tempFeature;
_formatFeatures[toNumber(Format::R5G6B5)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA4)] = tempFeature;
_formatFeatures[toNumber(Format::RGB5A1)] = tempFeature;
_formatFeatures[toNumber(Format::RGB10A2)] = tempFeature;
_formatFeatures[toNumber(Format::SRGB8)] = tempFeature;
_formatFeatures[toNumber(Format::SRGB8_A8)] = tempFeature;
_formatFeatures[toNumber(Format::R11G11B10F)] = tempFeature;
_formatFeatures[toNumber(Format::RGB9E5)] = tempFeature;
_formatFeatures[toNumber(Format::DEPTH)] = tempFeature;
_formatFeatures[toNumber(Format::DEPTH_STENCIL)] = tempFeature;
tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE;
_formatFeatures[toNumber(Format::R16F)] = tempFeature;
_formatFeatures[toNumber(Format::RG16F)] = tempFeature;
_formatFeatures[toNumber(Format::RGB16F)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA16F)] = tempFeature;
tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE;
_formatFeatures[toNumber(Format::R32F)] = tempFeature;
_formatFeatures[toNumber(Format::RG32F)] = tempFeature;
_formatFeatures[toNumber(Format::RGB32F)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA32F)] = tempFeature;
_formatFeatures[toNumber(Format::RGB10A2UI)] = FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE;
tempFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::RENDER_TARGET | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE | FormatFeature::VERTEX_ATTRIBUTE;
_formatFeatures[toNumber(Format::R8I)] = tempFeature;
_formatFeatures[toNumber(Format::R8UI)] = tempFeature;
_formatFeatures[toNumber(Format::R16I)] = tempFeature;
_formatFeatures[toNumber(Format::R16UI)] = tempFeature;
_formatFeatures[toNumber(Format::R32I)] = tempFeature;
_formatFeatures[toNumber(Format::R32UI)] = tempFeature;
_formatFeatures[toNumber(Format::RG8I)] = tempFeature;
_formatFeatures[toNumber(Format::RG8UI)] = tempFeature;
_formatFeatures[toNumber(Format::RG16I)] = tempFeature;
_formatFeatures[toNumber(Format::RG16UI)] = tempFeature;
_formatFeatures[toNumber(Format::RG32I)] = tempFeature;
_formatFeatures[toNumber(Format::RG32UI)] = tempFeature;
_formatFeatures[toNumber(Format::RGB8I)] = tempFeature;
_formatFeatures[toNumber(Format::RGB8UI)] = tempFeature;
_formatFeatures[toNumber(Format::RGB16I)] = tempFeature;
_formatFeatures[toNumber(Format::RGB16UI)] = tempFeature;
_formatFeatures[toNumber(Format::RGB32I)] = tempFeature;
_formatFeatures[toNumber(Format::RGB32UI)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA8I)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA8UI)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA16I)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA16UI)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA32I)] = tempFeature;
_formatFeatures[toNumber(Format::RGBA32UI)] = tempFeature;
_textureExclusive[toNumber(Format::R8)] = false;
_textureExclusive[toNumber(Format::RG8)] = false;
_textureExclusive[toNumber(Format::RGB8)] = false;
_textureExclusive[toNumber(Format::R5G6B5)] = false;
_textureExclusive[toNumber(Format::RGBA4)] = false;
_textureExclusive[toNumber(Format::RGB5A1)] = false;
_textureExclusive[toNumber(Format::RGBA8)] = false;
_textureExclusive[toNumber(Format::RGB10A2)] = false;
_textureExclusive[toNumber(Format::RGB10A2UI)] = false;
_textureExclusive[toNumber(Format::SRGB8_A8)] = false;
_textureExclusive[toNumber(Format::R8I)] = false;
_textureExclusive[toNumber(Format::R8UI)] = false;
_textureExclusive[toNumber(Format::R16I)] = false;
_textureExclusive[toNumber(Format::R16UI)] = false;
_textureExclusive[toNumber(Format::R32I)] = false;
_textureExclusive[toNumber(Format::R32UI)] = false;
_textureExclusive[toNumber(Format::RG8I)] = false;
_textureExclusive[toNumber(Format::RG8UI)] = false;
_textureExclusive[toNumber(Format::RG16I)] = false;
_textureExclusive[toNumber(Format::RG16UI)] = false;
_textureExclusive[toNumber(Format::RG32I)] = false;
_textureExclusive[toNumber(Format::RG32UI)] = false;
_textureExclusive[toNumber(Format::RGBA8I)] = false;
_textureExclusive[toNumber(Format::RGBA8UI)] = false;
_textureExclusive[toNumber(Format::RGBA16I)] = false;
_textureExclusive[toNumber(Format::RGBA16UI)] = false;
_textureExclusive[toNumber(Format::RGBA32I)] = false;
_textureExclusive[toNumber(Format::RGBA32UI)] = false;
_textureExclusive[toNumber(Format::DEPTH)] = false;
_textureExclusive[toNumber(Format::DEPTH_STENCIL)] = false;
if (checkExtension("render_snorm")) {
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_render_snorm.txt
// For 16, see https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_norm16.txt
_textureExclusive[toNumber(Format::R8SN)] = false;
_textureExclusive[toNumber(Format::RG8SN)] = false;
_textureExclusive[toNumber(Format::RGB8SN)] = false;
_textureExclusive[toNumber(Format::RGBA8SN)] = false;
}
if (checkExtension("color_buffer_float")) {
_formatFeatures[toNumber(Format::R32F)] |= FormatFeature::RENDER_TARGET;
_formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::RENDER_TARGET;
_formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::RENDER_TARGET;
_textureExclusive[toNumber(Format::R32F)] = false;
_textureExclusive[toNumber(Format::RG32F)] = false;
_textureExclusive[toNumber(Format::RGBA32F)] = false;
}
if (checkExtension("color_buffer_half_float")) {
_textureExclusive[toNumber(Format::R16F)] = false;
_textureExclusive[toNumber(Format::RG16F)] = false;
_textureExclusive[toNumber(Format::RGB16F)] = false;
_textureExclusive[toNumber(Format::RGBA16F)] = false;
}
if (checkExtension("texture_float_linear")) {
_formatFeatures[toNumber(Format::RGB32F)] |= FormatFeature::LINEAR_FILTER;
_formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::LINEAR_FILTER;
_formatFeatures[toNumber(Format::R32F)] |= FormatFeature::LINEAR_FILTER;
_formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::LINEAR_FILTER;
}
if (checkExtension("texture_half_float_linear")) {
_formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::LINEAR_FILTER;
_formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::LINEAR_FILTER;
_formatFeatures[toNumber(Format::R16F)] |= FormatFeature::LINEAR_FILTER;
_formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::LINEAR_FILTER;
}
const FormatFeature compressedFeature = FormatFeature::SAMPLED_TEXTURE | FormatFeature::LINEAR_FILTER;
if (checkExtension("compressed_ETC1")) {
_formatFeatures[toNumber(Format::ETC_RGB8)] = compressedFeature;
}
_formatFeatures[toNumber(Format::ETC2_RGB8)] = compressedFeature;
_formatFeatures[toNumber(Format::ETC2_RGBA8)] = compressedFeature;
_formatFeatures[toNumber(Format::ETC2_SRGB8)] = compressedFeature;
_formatFeatures[toNumber(Format::ETC2_SRGB8_A8)] = compressedFeature;
_formatFeatures[toNumber(Format::ETC2_RGB8_A1)] = compressedFeature;
_formatFeatures[toNumber(Format::ETC2_SRGB8_A1)] = compressedFeature;
if (checkExtension("texture_compression_pvrtc")) {
_formatFeatures[toNumber(Format::PVRTC_RGB2)] |= compressedFeature;
_formatFeatures[toNumber(Format::PVRTC_RGBA2)] |= compressedFeature;
_formatFeatures[toNumber(Format::PVRTC_RGB4)] |= compressedFeature;
_formatFeatures[toNumber(Format::PVRTC_RGBA4)] |= compressedFeature;
}
if (checkExtension("texture_compression_astc")) {
_formatFeatures[toNumber(Format::ASTC_RGBA_4X4)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_5X4)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_5X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_6X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_6X6)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_8X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_8X6)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_8X8)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_10X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_10X6)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_10X8)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_10X10)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_12X10)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_RGBA_12X12)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_4X4)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_5X4)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_5X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_6X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_6X6)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_8X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_8X6)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_8X8)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X5)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X6)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X8)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X10)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_12X10)] |= compressedFeature;
_formatFeatures[toNumber(Format::ASTC_SRGBA_12X12)] |= compressedFeature;
}
}
CommandBuffer *GLES3Device::createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) {
if (hasAgent || info.type == CommandBufferType::PRIMARY) return ccnew GLES3PrimaryCommandBuffer;
return ccnew GLES3CommandBuffer;
}
Queue *GLES3Device::createQueue() {
return ccnew GLES3Queue;
}
QueryPool *GLES3Device::createQueryPool() {
return ccnew GLES3QueryPool;
}
Swapchain *GLES3Device::createSwapchain() {
if (_xr) {
_xr->createXRSwapchains();
}
return ccnew GLES3Swapchain;
}
Buffer *GLES3Device::createBuffer() {
return ccnew GLES3Buffer;
}
Texture *GLES3Device::createTexture() {
return ccnew GLES3Texture;
}
Shader *GLES3Device::createShader() {
return ccnew GLES3Shader;
}
InputAssembler *GLES3Device::createInputAssembler() {
return ccnew GLES3InputAssembler;
}
RenderPass *GLES3Device::createRenderPass() {
return ccnew GLES3RenderPass;
}
Framebuffer *GLES3Device::createFramebuffer() {
return ccnew GLES3Framebuffer;
}
DescriptorSet *GLES3Device::createDescriptorSet() {
return ccnew GLES3DescriptorSet;
}
DescriptorSetLayout *GLES3Device::createDescriptorSetLayout() {
return ccnew GLES3DescriptorSetLayout;
}
PipelineLayout *GLES3Device::createPipelineLayout() {
return ccnew GLES3PipelineLayout;
}
PipelineState *GLES3Device::createPipelineState() {
return ccnew GLES3PipelineState;
}
Sampler *GLES3Device::createSampler(const SamplerInfo &info) {
return ccnew GLES3Sampler(info);
}
GeneralBarrier *GLES3Device::createGeneralBarrier(const GeneralBarrierInfo &info) {
return ccnew GLES3GeneralBarrier(info);
}
void GLES3Device::copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint32_t count) {
CC_PROFILE(GLES3DeviceCopyBuffersToTexture);
cmdFuncGLES3CopyBuffersToTexture(this, buffers, static_cast<GLES3Texture *>(dst)->gpuTexture(), regions, count);
}
void GLES3Device::copyTextureToBuffers(Texture *srcTexture, uint8_t *const *buffers, const BufferTextureCopy *regions, uint32_t count) {
CC_PROFILE(GLES3DeviceCopyTextureToBuffers);
cmdFuncGLES3CopyTextureToBuffers(this, static_cast<GLES3Texture *>(srcTexture)->gpuTextureView(), buffers, regions, count);
}
void GLES3Device::getQueryPoolResults(QueryPool *queryPool) {
CC_PROFILE(GLES3DeviceGetQueryPoolResults);
auto *cmdBuff = static_cast<GLES3CommandBuffer *>(getCommandBuffer());
cmdBuff->getQueryPoolResults(queryPool);
}
SampleCount GLES3Device::getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const {
return static_cast<SampleCount>(cmdFuncGLES3GetMaxSampleCount(this, format, usage, flags));
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,157 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "base/std/any.h"
#include "gfx-base/GFXDevice.h"
#include "gfx-gles-common/GLESCommandPool.h"
namespace cc {
class IXRInterface;
namespace gfx {
class GLES3GPUContext;
struct GLES3GPUSwapchain;
class GLES3GPUStateCache;
class GLES3GPUFramebufferHub;
struct GLES3GPUConstantRegistry;
class GLES3GPUFramebufferCacheMap;
class GLES3PipelineCache;
class CC_GLES3_API GLES3Device final : public Device {
public:
static GLES3Device *getInstance();
~GLES3Device() override;
using Device::copyBuffersToTexture;
using Device::createBuffer;
using Device::createCommandBuffer;
using Device::createDescriptorSet;
using Device::createDescriptorSetLayout;
using Device::createFramebuffer;
using Device::createGeneralBarrier;
using Device::createInputAssembler;
using Device::createPipelineLayout;
using Device::createPipelineState;
using Device::createQueryPool;
using Device::createQueue;
using Device::createRenderPass;
using Device::createSampler;
using Device::createShader;
using Device::createSwapchain;
using Device::createTexture;
using Device::createTextureBarrier;
void frameSync() override{};
void acquire(Swapchain *const *swapchains, uint32_t count) override;
void present() override;
inline const GLESBindingMapping &bindingMappings() const { return _bindingMappings; }
inline GLES3GPUContext *context() const { return _gpuContext; }
inline GLES3GPUStateCache *stateCache() const { return _gpuStateCache; }
inline GLES3GPUFramebufferHub *framebufferHub() const { return _gpuFramebufferHub; }
inline GLES3GPUConstantRegistry *constantRegistry() const { return _gpuConstantRegistry; }
inline GLES3GPUFramebufferCacheMap *framebufferCacheMap() const { return _gpuFramebufferCacheMap; }
inline GLES3PipelineCache *pipelineCache() const { return _pipelineCache.get(); }
inline bool checkExtension(const ccstd::string &extension) const {
return std::any_of(_extensions.begin(), _extensions.end(), [&extension](auto &ext) {
return ext.find(extension) != ccstd::string::npos;
});
}
inline uint8_t *getStagingBuffer(uint32_t size = 0) {
if (size > _stagingBufferSize) {
CC_FREE(_stagingBuffer);
_stagingBuffer = static_cast<uint8_t *>(CC_MALLOC(size));
_stagingBufferSize = size;
}
return _stagingBuffer;
}
inline bool isTextureExclusive(const Format &format) const { return _textureExclusive[static_cast<size_t>(format)]; };
SampleCount getMaxSampleCount(Format format, TextureUsage usage, TextureFlags flags) const override;
protected:
static GLES3Device *instance;
friend class DeviceManager;
GLES3Device();
bool doInit(const DeviceInfo &info) override;
void doDestroy() override;
CommandBuffer *createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) override;
Queue *createQueue() override;
QueryPool *createQueryPool() override;
Swapchain *createSwapchain() override;
Buffer *createBuffer() override;
Texture *createTexture() override;
Shader *createShader() override;
InputAssembler *createInputAssembler() override;
RenderPass *createRenderPass() override;
Framebuffer *createFramebuffer() override;
DescriptorSet *createDescriptorSet() override;
DescriptorSetLayout *createDescriptorSetLayout() override;
PipelineLayout *createPipelineLayout() override;
PipelineState *createPipelineState() override;
Sampler *createSampler(const SamplerInfo &info) override;
GeneralBarrier *createGeneralBarrier(const GeneralBarrierInfo &info) override;
void copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint32_t count) override;
void copyTextureToBuffers(Texture *src, uint8_t *const *buffers, const BufferTextureCopy *region, uint32_t count) override;
void getQueryPoolResults(QueryPool *queryPool) override;
void bindContext(bool bound) override;
void initFormatFeature();
GLES3GPUContext *_gpuContext{nullptr};
GLES3GPUStateCache *_gpuStateCache{nullptr};
GLES3GPUFramebufferHub *_gpuFramebufferHub{nullptr};
GLES3GPUConstantRegistry *_gpuConstantRegistry{nullptr};
GLES3GPUFramebufferCacheMap *_gpuFramebufferCacheMap{nullptr};
std::unique_ptr<GLES3PipelineCache> _pipelineCache;
ccstd::vector<GLES3GPUSwapchain *> _swapchains;
GLESBindingMapping _bindingMappings;
ccstd::vector<ccstd::string> _extensions;
ccstd::array<bool, static_cast<size_t>(Format::COUNT)> _textureExclusive;
uint8_t *_stagingBuffer{nullptr};
uint32_t _stagingBufferSize{0};
IXRInterface *_xr{nullptr};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,108 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3Framebuffer.h"
#include "GLES3RenderPass.h"
#include "GLES3Texture.h"
namespace cc {
namespace gfx {
GLES3Framebuffer::GLES3Framebuffer() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3Framebuffer::~GLES3Framebuffer() {
destroy();
}
void GLES3Framebuffer::updateExtent() {
if (!_colorTextures.empty()) {
const auto *tex = _colorTextures[0];
_gpuFBO->width = tex->getWidth();
_gpuFBO->height = tex->getHeight();
return;
}
if (_depthStencilTexture != nullptr) {
_gpuFBO->width = _depthStencilTexture->getWidth();
_gpuFBO->height = _depthStencilTexture->getHeight();
return;
}
}
void GLES3Framebuffer::doInit(const FramebufferInfo & /*info*/) {
_gpuFBO = ccnew GLES3GPUFramebuffer;
updateExtent();
_gpuFBO->gpuRenderPass = static_cast<GLES3RenderPass *>(_renderPass)->gpuRenderPass();
_gpuFBO->gpuColorViews.resize(_colorTextures.size());
for (size_t i = 0; i < _colorTextures.size(); ++i) {
auto *colorTexture = static_cast<GLES3Texture *>(_colorTextures.at(i));
_gpuFBO->gpuColorViews[i] = colorTexture->gpuTextureView();
GLES3Device::getInstance()->framebufferHub()->connect(colorTexture->gpuTexture(), _gpuFBO);
}
if (_depthStencilTexture) {
auto *depthTexture = static_cast<GLES3Texture *>(_depthStencilTexture);
_gpuFBO->gpuDepthStencilView = depthTexture->gpuTextureView();
GLES3Device::getInstance()->framebufferHub()->connect(depthTexture->gpuTexture(), _gpuFBO);
}
if (_depthStencilResolveTexture) {
auto *depthTexture = static_cast<GLES3Texture *>(_depthStencilResolveTexture);
_gpuFBO->gpuDepthStencilResolveView = depthTexture->gpuTextureView();
GLES3Device::getInstance()->framebufferHub()->connect(depthTexture->gpuTexture(), _gpuFBO);
}
cmdFuncGLES3CreateFramebuffer(GLES3Device::getInstance(), _gpuFBO);
}
void GLES3Framebuffer::doDestroy() {
if (_gpuFBO) {
cmdFuncGLES3DestroyFramebuffer(GLES3Device::getInstance(), _gpuFBO);
for (auto &texture : _colorTextures) {
auto *colorTexture = static_cast<GLES3Texture *>(texture);
GLES3Device::getInstance()->framebufferHub()->disengage(colorTexture->gpuTexture(), _gpuFBO);
}
if (_depthStencilTexture) {
auto *depthTexture = static_cast<GLES3Texture *>(_depthStencilTexture);
GLES3Device::getInstance()->framebufferHub()->disengage(depthTexture->gpuTexture(), _gpuFBO);
}
if (_depthStencilResolveTexture) {
auto *depthTexture = static_cast<GLES3Texture *>(_depthStencilResolveTexture);
GLES3Device::getInstance()->framebufferHub()->disengage(depthTexture->gpuTexture(), _gpuFBO);
}
delete _gpuFBO;
_gpuFBO = nullptr;
}
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,51 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXFramebuffer.h"
namespace cc {
namespace gfx {
class GLES3GPUFramebuffer;
class CC_GLES3_API GLES3Framebuffer final : public Framebuffer {
public:
GLES3Framebuffer();
~GLES3Framebuffer() override;
inline GLES3GPUFramebuffer *gpuFBO() const { return _gpuFBO; }
protected:
void doInit(const FramebufferInfo &info) override;
void doDestroy() override;
void updateExtent();
GLES3GPUFramebuffer *_gpuFBO = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,453 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 <thread>
#include "GLES3GPUObjects.h"
#include "base/StringUtil.h"
#if CC_SWAPPY_ENABLED
#include "swappy/swappyGL.h"
#endif
#define FORCE_DISABLE_VALIDATION 1
namespace cc {
namespace gfx {
#if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION
constexpr uint32_t DISABLE_VALIDATION_ASSERTIONS = 1; // 0 for default behavior, otherwise assertions will be disabled
void GL_APIENTRY GLES3EGLDebugProc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) {
String sourceDesc;
switch (source) {
case GL_DEBUG_SOURCE_API_KHR: sourceDesc = "API"; break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_KHR: sourceDesc = "SHADER_COMPILER"; break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR: sourceDesc = "WINDOW_SYSTEM"; break;
case GL_DEBUG_SOURCE_THIRD_PARTY_KHR: sourceDesc = "THIRD_PARTY"; break;
case GL_DEBUG_SOURCE_APPLICATION_KHR: sourceDesc = "APPLICATION"; break;
default: sourceDesc = "OTHER";
}
String typeDesc;
switch (type) {
case GL_DEBUG_TYPE_ERROR_KHR: typeDesc = "ERROR"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: typeDesc = "PEPRECATED_BEHAVIOR"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR: typeDesc = "UNDEFINED_BEHAVIOR"; break;
case GL_DEBUG_TYPE_PERFORMANCE_KHR: typeDesc = "PERFORMANCE"; break;
case GL_DEBUG_TYPE_PORTABILITY_KHR: typeDesc = "PORTABILITY"; break;
case GL_DEBUG_TYPE_MARKER_KHR: typeDesc = "MARKER"; break;
case GL_DEBUG_TYPE_PUSH_GROUP_KHR: typeDesc = "PUSH_GROUP"; break;
case GL_DEBUG_TYPE_POP_GROUP_KHR: typeDesc = "POP_GROUP"; break;
default: typeDesc = "OTHER";
}
String severityDesc;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH_KHR: severityDesc = "HIGH"; break;
case GL_DEBUG_SEVERITY_MEDIUM_KHR: severityDesc = "MEDIUM"; break;
case GL_DEBUG_SEVERITY_LOW_KHR: severityDesc = "LOW"; break;
default: severityDesc = "NOTIFICATION";
}
String msg = StringUtil::format("source: %s, type: %s, severity: %s, message: %s",
sourceDesc.c_str(), typeDesc.c_str(), severityDesc.c_str(), message);
if (severity == GL_DEBUG_SEVERITY_HIGH_KHR) {
CC_LOG_ERROR(msg.c_str());
CC_ASSERT(DISABLE_VALIDATION_ASSERTIONS);
} else if (severity == GL_DEBUG_SEVERITY_MEDIUM_KHR) {
CC_LOG_WARNING(msg.c_str());
} else {
CC_LOG_DEBUG(msg.c_str());
}
}
#endif
bool GLES3GPUContext::initialize(GLES3GPUStateCache *stateCache, GLES3GPUConstantRegistry *constantRegistry) {
_stateCache = stateCache;
_constantRegistry = constantRegistry;
if (!gles3wInit()) {
return false;
}
EGL_CHECK(eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY));
if (eglDisplay == EGL_NO_DISPLAY) {
CC_LOG_ERROR("eglGetDisplay() - FAILED.");
return false;
}
EGLBoolean success{false};
EGL_CHECK(success = eglInitialize(eglDisplay, &eglMajorVersion, &eglMinorVersion));
if (!success) {
CC_LOG_ERROR("eglInitialize() - FAILED.");
return false;
}
EGL_CHECK(eglBindAPI(EGL_OPENGL_ES_API));
bool msaaEnabled{false};
bool qualityPreferred{false};
EGLint redSize{8};
EGLint greenSize{8};
EGLint blueSize{8};
EGLint alphaSize{8};
EGLint depthSize{24};
EGLint stencilSize{8};
EGLint sampleBufferSize{msaaEnabled ? EGL_DONT_CARE : 0};
EGLint sampleSize{msaaEnabled ? EGL_DONT_CARE : 0};
EGLint defaultAttribs[]{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
EGL_BLUE_SIZE, blueSize,
EGL_GREEN_SIZE, greenSize,
EGL_RED_SIZE, redSize,
EGL_ALPHA_SIZE, alphaSize,
EGL_DEPTH_SIZE, depthSize,
EGL_STENCIL_SIZE, stencilSize,
EGL_SAMPLE_BUFFERS, sampleBufferSize,
EGL_SAMPLES, sampleSize,
EGL_NONE};
int numConfig{0};
ccstd::vector<EGLConfig> eglConfigs;
success = eglChooseConfig(eglDisplay, defaultAttribs, nullptr, 0, &numConfig);
if (success) {
eglConfigs.resize(numConfig);
} else {
CC_LOG_ERROR("Query GLES3 configuration failed.");
return false;
}
int count = numConfig;
EGL_CHECK(success = eglChooseConfig(eglDisplay, defaultAttribs, eglConfigs.data(), count, &numConfig));
if (!success || !numConfig) {
CC_LOG_ERROR("eglChooseConfig configuration failed.");
return false;
}
EGLint depth{0};
EGLint stencil{0};
EGLint sampleBuffers{0};
EGLint sampleCount{0};
EGLint params[8]{0};
uint64_t lastScore = qualityPreferred ? std::numeric_limits<uint64_t>::min() : std::numeric_limits<uint64_t>::max();
for (int i = 0; i < numConfig; i++) {
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_RED_SIZE, &params[0]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_GREEN_SIZE, &params[1]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_BLUE_SIZE, &params[2]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_ALPHA_SIZE, &params[3]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_DEPTH_SIZE, &params[4]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_STENCIL_SIZE, &params[5]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_SAMPLE_BUFFERS, &params[6]);
eglGetConfigAttrib(eglDisplay, eglConfigs[i], EGL_SAMPLES, &params[7]);
int bNonLinearDepth = 0;
/*------------------------------------------ANGLE's priority-----------------------------------------------*/
// Favor EGLConfigLists by RGB, then Depth, then Non-linear Depth, then Stencil, then Alpha
uint64_t currScore{0};
EGLint colorScore = std::abs(params[0] - redSize) + std::abs(params[1] - greenSize) + std::abs(params[2] - blueSize);
currScore |= static_cast<uint64_t>(std::min(std::max(params[6], 0), 15)) << 29;
currScore |= static_cast<uint64_t>(std::min(std::max(params[7], 0), 31)) << 24;
currScore |= static_cast<uint64_t>(std::min(colorScore, 127)) << 17;
currScore |= static_cast<uint64_t>(std::min(std::abs(params[4] - depthSize), 63)) << 11;
currScore |= static_cast<uint64_t>(std::min(std::abs(1 - bNonLinearDepth), 1)) << 10;
currScore |= static_cast<uint64_t>(std::min(std::abs(params[5] - stencilSize), 31)) << 6;
currScore |= static_cast<uint64_t>(std::min(std::abs(params[3] - alphaSize), 31)) << 0;
/*------------------------------------------ANGLE's priority-----------------------------------------------*/
// if msaaEnabled, sampleBuffers and sampleCount should be greater than 0, until iterate to the last one(can't find).
bool msaaLimit = (msaaEnabled ? (params[6] > 0 && params[7] > 0) : (params[6] == 0 && params[7] == 0));
// performancePreferred ? [>=] : [<] , egl configurations store in "ascending order"
bool filter = (currScore < lastScore) ^ qualityPreferred;
if ((filter && msaaLimit) || (!eglConfig && i == numConfig - 1)) {
eglConfig = eglConfigs[i];
depth = params[4];
stencil = params[5];
sampleBuffers = params[6];
sampleCount = params[7];
lastScore = currScore;
}
}
CC_LOG_INFO("Setup EGLConfig: depth [%d] stencil [%d] sampleBuffer [%d] sampleCount [%d]", depth, stencil, sampleBuffers, sampleCount);
EGL_CHECK(_extensions = StringUtil::split(eglQueryString(eglDisplay, EGL_EXTENSIONS), " "));
bool hasKHRCreateCtx = checkExtension(CC_TOSTR(EGL_KHR_create_context));
if (hasKHRCreateCtx) {
eglAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
eglAttributes.push_back(3);
eglAttributes.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
eglAttributes.push_back(2);
#if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION
eglAttributes.push_back(EGL_CONTEXT_FLAGS_KHR);
eglAttributes.push_back(EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR);
#endif
eglAttributes.push_back(EGL_NONE);
for (int m = 2; m >= 0; --m) {
eglAttributes[3] = m;
eglDefaultContext = eglCreateContext(eglDisplay, eglConfig, nullptr, eglAttributes.data());
EGLint err = eglGetError(); // QNX throws egl errors on mismatch
if (eglDefaultContext && err == EGL_SUCCESS) {
_constantRegistry->glMinorVersion = m;
break;
}
}
} else {
eglAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
eglAttributes.push_back(3);
eglAttributes.push_back(EGL_NONE);
EGL_CHECK(eglDefaultContext = eglCreateContext(eglDisplay, eglConfig, nullptr, eglAttributes.data()));
}
if (!eglDefaultContext) {
CC_LOG_ERROR("Create EGL context failed.");
return false;
}
EGLint pbufferAttribs[]{
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE};
EGL_CHECK(eglDefaultSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs));
size_t threadID{std::hash<std::thread::id>{}(std::this_thread::get_id())};
_sharedContexts[threadID] = eglDefaultContext;
bindContext(true);
return true;
}
void GLES3GPUContext::destroy() {
if (eglDisplay) {
makeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (eglDefaultSurface) {
EGL_CHECK(eglDestroySurface(eglDisplay, eglDefaultSurface));
eglDefaultSurface = EGL_NO_SURFACE;
}
for (auto pair : _sharedContexts) {
if (pair.second != eglDefaultContext) {
EGL_CHECK(eglDestroyContext(eglDisplay, pair.second));
}
}
_sharedContexts.clear();
if (eglDefaultContext) {
EGL_CHECK(eglDestroyContext(eglDisplay, eglDefaultContext));
eglDefaultContext = EGL_NO_SURFACE;
}
if (eglDisplay) {
EGL_CHECK(eglTerminate(eglDisplay));
eglDisplay = EGL_NO_DISPLAY;
}
gles3wExit();
}
void GLES3GPUContext::bindContext(bool bound) {
if (bound) {
makeCurrent(eglDefaultSurface, eglDefaultSurface, eglDefaultContext);
resetStates();
} else {
makeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT, false);
_eglCurrentDrawSurface = EGL_NO_SURFACE;
_eglCurrentReadSurface = EGL_NO_SURFACE;
}
}
void GLES3GPUContext::makeCurrent(const GLES3GPUSwapchain *drawSwapchain, const GLES3GPUSwapchain *readSwapchain) {
EGLSurface drawSurface = drawSwapchain ? drawSwapchain->eglSurface : _eglCurrentDrawSurface;
EGLSurface readSurface = readSwapchain ? readSwapchain->eglSurface : _eglCurrentReadSurface;
EGLContext prevContext = eglGetCurrentContext();
if (_eglCurrentDrawSurface == drawSurface && _eglCurrentReadSurface == readSurface && _eglCurrentContext == prevContext) {
return;
}
makeCurrent(drawSurface, readSurface, _eglCurrentContext);
if (prevContext != _eglCurrentContext) {
resetStates();
}
}
void GLES3GPUContext::present(const GLES3GPUSwapchain *swapchain) {
#if CC_SWAPPY_ENABLED
if (swapchain->swappyEnabled) {
// fallback to normal eglswap if swappy swap failed.
if (SwappyGL_swap(eglDisplay, swapchain->eglSurface)) {
return;
}
}
#endif
// For an example, 2 windows changed to background will cause the eglSurface of both destroyed,
// and then make one of them foreground, and the other window's eglSurface will stays EGL_NO_SURFACE.
// But in GLES3Device::present it iterates all swapchains, and now the second window containing the invalid surface exists.
if (swapchain->eglSurface == EGL_NO_SURFACE) {
return;
}
if (_eglCurrentInterval != swapchain->eglSwapInterval) {
if (!eglSwapInterval(eglDisplay, swapchain->eglSwapInterval)) {
CC_LOG_ERROR("eglSwapInterval() - FAILED.");
}
_eglCurrentInterval = swapchain->eglSwapInterval;
}
makeCurrent(swapchain, swapchain);
EGL_CHECK(eglSwapBuffers(eglDisplay, swapchain->eglSurface));
}
EGLContext GLES3GPUContext::getSharedContext() {
size_t threadID{std::hash<std::thread::id>{}(std::this_thread::get_id())};
if (_sharedContexts.count(threadID)) return _sharedContexts[threadID];
EGLContext context = EGL_NO_CONTEXT;
EGL_CHECK(context = eglCreateContext(eglDisplay, eglConfig, eglDefaultContext, eglAttributes.data()));
if (!context) {
CC_LOG_ERROR("Create shared context failed.");
return EGL_NO_CONTEXT;
}
_sharedContexts[threadID] = context;
return context;
}
bool GLES3GPUContext::makeCurrent(EGLSurface drawSurface, EGLSurface readSurface, EGLContext context, bool updateCache) {
bool succeeded;
EGL_CHECK(succeeded = eglMakeCurrent(eglDisplay, drawSurface, readSurface, context));
if (succeeded && updateCache) {
_eglCurrentDrawSurface = drawSurface;
_eglCurrentReadSurface = readSurface;
_eglCurrentContext = context;
}
return succeeded;
}
// NOLINTNEXTLINE(google-readability-function-size, readability-function-size)
void GLES3GPUContext::resetStates() const {
GL_CHECK(glPixelStorei(GL_PACK_ALIGNMENT, 1));
GL_CHECK(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
GL_CHECK(glActiveTexture(GL_TEXTURE0));
//////////////////////////////////////////////////////////////////////////
GL_CHECK(glEnable(GL_SCISSOR_TEST));
GL_CHECK(glEnable(GL_CULL_FACE));
GL_CHECK(glCullFace(GL_BACK));
GL_CHECK(glFrontFace(GL_CCW));
GL_CHECK(glDisable(GL_SAMPLE_COVERAGE));
//////////////////////////////////////////////////////////////////////////
GL_CHECK(glEnable(GL_DEPTH_TEST));
GL_CHECK(glDepthMask(GL_TRUE));
GL_CHECK(glDepthFunc(GL_LESS));
GL_CHECK(glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 1, 0xffffffff));
GL_CHECK(glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP));
GL_CHECK(glStencilMaskSeparate(GL_FRONT, 0xffffffff));
GL_CHECK(glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 1, 0xffffffff));
GL_CHECK(glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP));
GL_CHECK(glStencilMaskSeparate(GL_BACK, 0xffffffff));
GL_CHECK(glDisable(GL_STENCIL_TEST));
//////////////////////////////////////////////////////////////////////////
GL_CHECK(glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE));
GL_CHECK(glDisable(GL_BLEND));
GL_CHECK(glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD));
GL_CHECK(glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO));
GL_CHECK(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
GL_CHECK(glBlendColor(0.0F, 0.0F, 0.0F, 0.0F));
GL_CHECK(glUseProgram(0));
GL_CHECK(glBindVertexArray(0));
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_COPY_READ_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_COPY_WRITE_BUFFER, 0));
if (_constantRegistry->glMinorVersion) {
GL_CHECK(glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0));
GL_CHECK(glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0));
}
GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
GL_CHECK(glBindTexture(GL_TEXTURE_3D, 0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, 0));
GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, 0));
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
#if CC_DEBUG > 0 && !FORCE_DISABLE_VALIDATION
GL_CHECK(glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR));
if (glDebugMessageControlKHR) {
GL_CHECK(glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE));
}
if (glDebugMessageCallbackKHR) {
GL_CHECK(glDebugMessageCallbackKHR(GLES3EGLDebugProc, NULL));
}
#endif
if (_constantRegistry->mFBF == FBFSupportLevel::NON_COHERENT_QCOM) {
GL_CHECK(glEnable(GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM));
}
_stateCache->reset();
_constantRegistry->currentBoundThreadID = std::hash<std::thread::id>{}(std::this_thread::get_id());
CC_LOG_DEBUG("EGL context bounded to thread %llx", _constantRegistry->currentBoundThreadID);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,686 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include <algorithm>
#include <unordered_map>
#include "base/Macros.h"
#include "base/std/container/unordered_map.h"
#include "gfx-base/GFXDef-common.h"
#include "gfx-base/GFXDef.h"
#include "gfx-base/GFXDeviceObject.h"
#include "gfx-gles-common/GLESCommandPool.h"
#include "GLES3Std.h"
#include "GLES3Wrangler.h"
namespace cc {
namespace gfx {
struct GLES3GPUConstantRegistry {
size_t currentBoundThreadID{0U};
uint32_t glMinorVersion{0U};
MSRTSupportLevel mMSRT{MSRTSupportLevel::NONE};
FBFSupportLevel mFBF{FBFSupportLevel::NONE};
bool debugMarker = false;
};
class GLES3GPUStateCache;
struct GLES3GPUSwapchain;
class GLES3GPUContext final {
public:
bool initialize(GLES3GPUStateCache *stateCache, GLES3GPUConstantRegistry *constantRegistry);
void destroy();
EGLint eglMajorVersion{0};
EGLint eglMinorVersion{0};
EGLDisplay eglDisplay{EGL_NO_DISPLAY};
EGLConfig eglConfig{nullptr};
ccstd::vector<EGLint> eglAttributes;
EGLSurface eglDefaultSurface{EGL_NO_SURFACE};
EGLContext eglDefaultContext{EGL_NO_CONTEXT};
// pass nullptr to keep the current surface
void makeCurrent(const GLES3GPUSwapchain *drawSwapchain = nullptr, const GLES3GPUSwapchain *readSwapchain = nullptr);
void bindContext(bool bound); // for context switching between threads
void present(const GLES3GPUSwapchain *swapchain);
inline bool checkExtension(const ccstd::string &extension) const {
return std::find(_extensions.begin(), _extensions.end(), extension) != _extensions.end();
}
private:
bool makeCurrent(EGLSurface drawSurface, EGLSurface readSurface, EGLContext context, bool updateCache = true);
EGLContext getSharedContext();
void resetStates() const;
// state caches
EGLSurface _eglCurrentDrawSurface{EGL_NO_SURFACE};
EGLSurface _eglCurrentReadSurface{EGL_NO_SURFACE};
EGLContext _eglCurrentContext{EGL_NO_CONTEXT};
EGLint _eglCurrentInterval{0};
GLES3GPUStateCache *_stateCache{nullptr};
GLES3GPUConstantRegistry *_constantRegistry{nullptr};
ccstd::unordered_map<size_t, EGLContext> _sharedContexts;
ccstd::vector<ccstd::string> _extensions;
};
class GLES3GPUQueryPool final {
public:
QueryType type{QueryType::OCCLUSION};
uint32_t maxQueryObjects{0};
bool forceWait{true};
ccstd::vector<GLuint> glQueryIds;
inline GLuint mapGLQueryId(uint32_t queryId) {
if (queryId < maxQueryObjects) {
return glQueryIds[queryId];
}
return UINT_MAX;
}
};
struct GLES3GPUBuffer {
BufferUsage usage = BufferUsage::NONE;
MemoryUsage memUsage = MemoryUsage::NONE;
uint32_t size = 0;
uint32_t stride = 0;
uint32_t count = 0;
GLenum glTarget = 0;
GLuint glBuffer = 0;
GLuint glOffset = 0;
uint8_t *buffer = nullptr;
DrawInfoList indirects;
};
using GLES3GPUBufferList = ccstd::vector<GLES3GPUBuffer *>;
struct GLES3GPUTexture {
TextureType type{TextureType::TEX2D};
Format format{Format::UNKNOWN};
TextureUsage usage{TextureUsageBit::NONE};
uint32_t width{0};
uint32_t height{0};
uint32_t depth{1};
uint32_t size{0};
uint32_t arrayLayer{1};
uint32_t mipLevel{1};
TextureFlags flags{TextureFlagBit::NONE};
bool immutable{true};
bool isPowerOf2{false};
bool useRenderBuffer{false};
bool memoryAllocated{true}; // false if swapchain image or implicit ms render buffer.
GLenum glInternalFmt{0};
GLenum glFormat{0};
GLenum glType{0};
GLenum glUsage{0};
GLint glSamples{0};
GLuint glTexture{0};
GLuint glRenderbuffer{0};
GLenum glWrapS{0};
GLenum glWrapT{0};
GLenum glMinFilter{0};
GLenum glMagFilter{0};
GLES3GPUSwapchain *swapchain{nullptr};
};
struct GLES3GPUTextureView {
GLES3GPUTexture *gpuTexture{nullptr};
TextureType type = TextureType::TEX2D;
Format format = Format::UNKNOWN;
uint32_t baseLevel = 0U;
uint32_t levelCount = 1U;
uint32_t baseLayer = 0U;
uint32_t layerCount = 1U;
uint32_t basePlane = 0U;
uint32_t planeCount = 0U;
GLenum glTarget{0};
};
using GLES3GPUTextureViewList = ccstd::vector<GLES3GPUTextureView *>;
struct GLES3GPUSwapchain {
#if CC_SWAPPY_ENABLED
bool swappyEnabled{false};
#endif
EGLSurface eglSurface{EGL_NO_SURFACE};
EGLint eglSwapInterval{0};
GLuint glFramebuffer{0};
GLES3GPUTexture *gpuColorTexture{nullptr};
bool isXR{false};
};
class GLES3GPUSampler final {
public:
Filter minFilter = Filter::NONE;
Filter magFilter = Filter::NONE;
Filter mipFilter = Filter::NONE;
Address addressU = Address::CLAMP;
Address addressV = Address::CLAMP;
Address addressW = Address::CLAMP;
GLenum glMinFilter = 0;
GLenum glMagFilter = 0;
GLenum glWrapS = 0;
GLenum glWrapT = 0;
GLenum glWrapR = 0;
~GLES3GPUSampler() {
ccstd::vector<GLuint> glSampelrs;
for (const auto &pair : _cache) {
glSampelrs.push_back(pair.second);
}
GL_CHECK(glDeleteSamplers(static_cast<GLsizei>(glSampelrs.size()), glSampelrs.data()));
}
GLuint getGLSampler(uint16_t minLod, uint16_t maxLod);
private:
ccstd::unordered_map<uint32_t, GLuint> _cache;
};
struct GLES3GPUInput {
uint32_t binding = 0;
ccstd::string name;
Type type = Type::UNKNOWN;
uint32_t stride = 0;
uint32_t count = 0;
uint32_t size = 0;
GLenum glType = 0;
GLint glLoc = -1;
};
using GLES3GPUInputList = ccstd::vector<GLES3GPUInput>;
struct GLES3GPUUniform {
uint32_t binding = INVALID_BINDING;
ccstd::string name;
Type type = Type::UNKNOWN;
uint32_t stride = 0;
uint32_t count = 0;
uint32_t size = 0;
uint32_t offset = 0;
GLenum glType = 0;
GLint glLoc = -1;
};
using GLES3GPUUniformList = ccstd::vector<GLES3GPUUniform>;
struct GLES3GPUUniformBuffer {
uint32_t set = INVALID_BINDING;
uint32_t binding = INVALID_BINDING;
ccstd::string name;
uint32_t size = 0;
uint32_t glBinding = 0xffffffff;
bool isStorage = false;
};
using GLES3GPUUniformBufferList = ccstd::vector<GLES3GPUUniformBuffer>;
struct GLES3GPUUniformSamplerTexture {
uint32_t set = 0;
uint32_t binding = 0;
ccstd::string name;
Type type = Type::UNKNOWN;
uint32_t count = 0U;
ccstd::vector<GLint> units;
GLenum glType = 0;
GLint glLoc = -1;
};
using GLES3GPUUniformSamplerTextureList = ccstd::vector<GLES3GPUUniformSamplerTexture>;
struct GLES3GPUUniformStorageImage {
uint32_t set = 0;
uint32_t binding = 0;
ccstd::string name;
Type type = Type::UNKNOWN;
uint32_t count = 0U;
ccstd::vector<int> units;
GLenum glMemoryAccess = GL_READ_WRITE;
GLint glLoc = -1;
};
using GLES3GPUUniformStorageImageList = ccstd::vector<GLES3GPUUniformStorageImage>;
struct GLES3GPUShaderStage {
GLES3GPUShaderStage(ShaderStageFlagBit t, ccstd::string s, GLuint shader = 0)
: type(t),
source(std::move(std::move(s))),
glShader(shader) {}
ShaderStageFlagBit type;
ccstd::string source;
GLuint glShader = 0;
};
using GLES3GPUShaderStageList = ccstd::vector<GLES3GPUShaderStage>;
struct GLES3GPUShader {
ccstd::string name;
UniformBlockList blocks;
UniformStorageBufferList buffers;
UniformSamplerTextureList samplerTextures;
UniformSamplerList samplers;
UniformTextureList textures;
UniformStorageImageList images;
UniformInputAttachmentList subpassInputs;
GLES3GPUShaderStageList gpuStages;
GLuint glProgram = 0;
ccstd::hash_t hash = INVALID_SHADER_HASH;
GLES3GPUInputList glInputs;
GLES3GPUUniformBufferList glBuffers;
GLES3GPUUniformSamplerTextureList glSamplerTextures;
GLES3GPUUniformStorageImageList glImages;
};
struct GLES3GPUAttribute {
ccstd::string name;
GLuint glBuffer = 0;
GLenum glType = 0;
uint32_t size = 0;
uint32_t count = 0;
uint32_t stride = 1;
uint32_t componentCount = 1;
bool isNormalized = false;
bool isInstanced = false;
uint32_t offset = 0;
};
using GLES3GPUAttributeList = ccstd::vector<GLES3GPUAttribute>;
struct GLES3GPUInputAssembler {
AttributeList attributes;
GLES3GPUBufferList gpuVertexBuffers;
GLES3GPUBuffer *gpuIndexBuffer = nullptr;
GLES3GPUBuffer *gpuIndirectBuffer = nullptr;
GLES3GPUAttributeList glAttribs;
GLenum glIndexType = 0;
ccstd::unordered_map<size_t, GLuint> glVAOs;
};
struct GLES3GPUGeneralBarrier {
AccessFlags prevAccesses = AccessFlagBit::NONE;
AccessFlags nextAccesses = AccessFlagBit::NONE;
GLbitfield glBarriers = 0U;
GLbitfield glBarriersByRegion = 0U;
};
using DrawBuffer = ccstd::vector<GLenum>;
struct GLES3GPURenderPass {
ColorAttachmentList colorAttachments;
DepthStencilAttachment depthStencilAttachment;
DepthStencilAttachment depthStencilResolveAttachment;
SubpassInfoList subpasses;
SubpassDependencyList dependencies;
ccstd::vector<uint32_t> colors;
ccstd::vector<uint32_t> resolves;
uint32_t depthStencil = INVALID_BINDING;
uint32_t depthStencilResolve = INVALID_BINDING;
ccstd::vector<uint32_t> indices; // offsets to GL_COLOR_ATTACHMENT_0
ccstd::vector<DrawBuffer> drawBuffers;
};
class GLES3GPUFramebufferCacheMap;
struct GLES3GPUFramebufferObject {
void initialize(GLES3GPUSwapchain *swc = nullptr);
void bindColor(const GLES3GPUTextureView *texture, uint32_t colorIndex, const ColorAttachment &attachment);
void bindColorMultiSample(const GLES3GPUTextureView *texture, uint32_t colorIndex, GLint samples, const ColorAttachment &attachment);
void bindDepthStencil(const GLES3GPUTextureView *texture, const DepthStencilAttachment &attachment);
void bindDepthStencilMultiSample(const GLES3GPUTextureView *texture, GLint samples, const DepthStencilAttachment &attachment);
bool isActive() const;
void finalize(GLES3GPUStateCache *cache);
void processLoad(GLenum target);
void processStore(GLenum target);
void destroy(GLES3GPUStateCache *cache, GLES3GPUFramebufferCacheMap *framebufferCacheMap);
GLuint getHandle() const { return swapchain != nullptr ? swapchain->glFramebuffer : handle; }
using Reference = std::pair<const GLES3GPUTextureView*, GLint>;
GLES3GPUSwapchain *swapchain{nullptr};
ccstd::vector<Reference> colors;
Reference depthStencil{nullptr, 1};
GLenum dsAttachment{GL_NONE};
ccstd::vector<GLenum> loadInvalidates;
ccstd::vector<GLenum> storeInvalidates;
private:
GLuint handle{0};
};
class GLES3GPUFramebuffer final {
public:
GLES3GPURenderPass *gpuRenderPass{nullptr};
GLES3GPUTextureViewList gpuColorViews;
GLES3GPUTextureView *gpuDepthStencilView{nullptr};
GLES3GPUTextureView *gpuDepthStencilResolveView{nullptr};
uint32_t width{UINT_MAX};
uint32_t height{UINT_MAX};
GLbitfield dsResolveMask = 0;
std::vector<std::pair<uint32_t, uint32_t>> colorBlitPairs;
GLES3GPUFramebufferObject framebuffer;
GLES3GPUFramebufferObject resolveFramebuffer;
};
struct GLES3GPUDescriptorSetLayout {
DescriptorSetLayoutBindingList bindings;
ccstd::vector<uint32_t> dynamicBindings;
ccstd::vector<uint32_t> bindingIndices;
ccstd::vector<uint32_t> descriptorIndices;
uint32_t descriptorCount = 0U;
ccstd::hash_t hash = 0U;
};
using GLES3GPUDescriptorSetLayoutList = ccstd::vector<GLES3GPUDescriptorSetLayout *>;
struct GLES3GPUPipelineLayout {
GLES3GPUDescriptorSetLayoutList setLayouts;
// helper storages
ccstd::vector<ccstd::vector<int>> dynamicOffsetIndices;
ccstd::vector<uint32_t> dynamicOffsetOffsets;
ccstd::vector<uint32_t> dynamicOffsets;
uint32_t dynamicOffsetCount = 0U;
ccstd::hash_t hash = 0U;
};
struct GLES3GPUPipelineState {
GLenum glPrimitive = GL_TRIANGLES;
GLES3GPUShader *gpuShader = nullptr;
RasterizerState rs;
DepthStencilState dss;
BlendState bs;
DynamicStateList dynamicStates;
GLES3GPUPipelineLayout *gpuLayout = nullptr;
GLES3GPURenderPass *gpuRenderPass = nullptr;
GLES3GPUPipelineLayout *gpuPipelineLayout = nullptr;
};
struct GLES3GPUDescriptor {
DescriptorType type = DescriptorType::UNKNOWN;
GLES3GPUBuffer *gpuBuffer = nullptr;
GLES3GPUTextureView *gpuTextureView = nullptr;
GLES3GPUSampler *gpuSampler = nullptr;
};
using GLES3GPUDescriptorList = ccstd::vector<GLES3GPUDescriptor>;
struct GLES3GPUDescriptorSet {
GLES3GPUDescriptorList gpuDescriptors;
const ccstd::vector<uint32_t> *descriptorIndices = nullptr;
};
struct GLES3GPUDispatchInfo {
uint32_t groupCountX = 0;
uint32_t groupCountY = 0;
uint32_t groupCountZ = 0;
GLES3GPUBuffer *indirectBuffer = nullptr;
uint32_t indirectOffset = 0;
};
struct GLES3ObjectCache {
uint32_t subpassIdx = 0U;
GLES3GPURenderPass *gpuRenderPass = nullptr;
GLES3GPUFramebuffer *gpuFramebuffer = nullptr;
GLES3GPUPipelineState *gpuPipelineState = nullptr;
GLES3GPUInputAssembler *gpuInputAssembler = nullptr;
GLenum glPrimitive = 0;
Rect renderArea;
ColorList clearColors;
float clearDepth = 1.F;
uint32_t clearStencil = 0U;
};
class GLES3GPUStateCache final {
public:
GLuint glArrayBuffer = 0;
GLuint glElementArrayBuffer = 0;
GLuint glUniformBuffer = 0;
ccstd::vector<GLuint> glBindUBOs;
ccstd::vector<GLuint> glBindUBOOffsets;
GLuint glShaderStorageBuffer = 0;
ccstd::vector<GLuint> glBindSSBOs;
ccstd::vector<GLuint> glBindSSBOOffsets;
GLuint glDispatchIndirectBuffer = 0;
GLuint glVAO = 0;
uint32_t texUint = 0;
ccstd::vector<GLuint> glTextures;
ccstd::vector<GLuint> glImages;
ccstd::vector<GLuint> glSamplers;
GLuint glProgram = 0;
ccstd::vector<bool> glEnabledAttribLocs;
ccstd::vector<bool> glCurrentAttribLocs;
GLuint glReadFramebuffer = 0;
GLuint glDrawFramebuffer = 0;
GLuint glRenderbuffer = 0;
Viewport viewport;
Rect scissor;
RasterizerState rs;
DepthStencilState dss;
BlendState bs;
bool isCullFaceEnabled = true;
bool isStencilTestEnabled = false;
ccstd::unordered_map<ccstd::string, uint32_t> texUnitCacheMap;
GLES3ObjectCache gfxStateCache;
void initialize(size_t texUnits, size_t imageUnits, size_t uboBindings, size_t ssboBindings, size_t vertexAttributes) {
glBindUBOs.resize(uboBindings, 0U);
glBindUBOOffsets.resize(uboBindings, 0U);
glBindSSBOs.resize(ssboBindings, 0U);
glBindSSBOOffsets.resize(ssboBindings, 0U);
glTextures.resize(texUnits, 0U);
glSamplers.resize(texUnits, 0U);
glImages.resize(imageUnits, 0U);
glEnabledAttribLocs.resize(vertexAttributes, false);
glCurrentAttribLocs.resize(vertexAttributes, false);
_initialized = true;
}
void reset() {
if (!_initialized) return;
glArrayBuffer = 0;
glElementArrayBuffer = 0;
glUniformBuffer = 0;
glBindUBOs.assign(glBindUBOs.size(), 0U);
glBindUBOOffsets.assign(glBindUBOOffsets.size(), 0U);
glShaderStorageBuffer = 0;
glBindSSBOs.assign(glBindSSBOs.size(), 0U);
glBindSSBOOffsets.assign(glBindSSBOOffsets.size(), 0U);
glDispatchIndirectBuffer = 0;
glVAO = 0;
texUint = 0;
glTextures.assign(glTextures.size(), 0U);
glImages.assign(glImages.size(), 0U);
glSamplers.assign(glSamplers.size(), 0U);
glProgram = 0;
glEnabledAttribLocs.assign(glEnabledAttribLocs.size(), false);
glCurrentAttribLocs.assign(glCurrentAttribLocs.size(), false);
glReadFramebuffer = 0;
glDrawFramebuffer = 0;
glRenderbuffer = 0;
isCullFaceEnabled = true;
isStencilTestEnabled = false;
viewport = Viewport();
scissor = Rect();
rs = RasterizerState();
dss = DepthStencilState();
bs = BlendState();
gfxStateCache.gpuRenderPass = nullptr;
gfxStateCache.gpuFramebuffer = nullptr;
gfxStateCache.gpuPipelineState = nullptr;
gfxStateCache.gpuInputAssembler = nullptr;
gfxStateCache.glPrimitive = 0U;
gfxStateCache.subpassIdx = 0U;
}
private:
bool _initialized{false};
};
class GLES3GPUFramebufferCacheMap final {
public:
explicit GLES3GPUFramebufferCacheMap(GLES3GPUStateCache *cache) : _cache(cache) {}
void registerExternal(GLuint glFramebuffer, const GLES3GPUTexture *gpuTexture, uint32_t mipLevel) {
bool isTexture = gpuTexture->glTexture;
GLuint glResource = isTexture ? gpuTexture->glTexture : gpuTexture->glRenderbuffer;
auto &cacheMap = isTexture ? _textureMap : _renderbufferMap;
if (cacheMap[glResource].empty()) cacheMap[glResource].resize(gpuTexture->mipLevel);
if (!cacheMap[glResource][mipLevel].glFramebuffer) {
cacheMap[glResource][mipLevel] = {glFramebuffer, true};
}
}
void unregisterExternal(GLuint glFramebuffer) {
for (auto &levels : _textureMap) {
for (auto &fbo : levels.second) {
if (fbo.glFramebuffer == glFramebuffer) {
fbo.glFramebuffer = 0;
return;
}
}
}
for (auto &levels : _renderbufferMap) {
for (auto &fbo : levels.second) {
if (fbo.glFramebuffer == glFramebuffer) {
fbo.glFramebuffer = 0;
return;
}
}
}
}
GLuint getFramebufferFromTexture(const GLES3GPUTextureView *gpuTextureView, const TextureSubresLayers &subres) {
const auto *gpuTexture = gpuTextureView->gpuTexture;
bool isTexture = gpuTexture->glTexture;
GLuint glResource = isTexture ? gpuTexture->glTexture : gpuTexture->glRenderbuffer;
auto &cacheMap = isTexture ? _textureMap : _renderbufferMap;
uint32_t mipLevel = isTexture ? subres.mipLevel : 0;
if (gpuTexture->swapchain) return gpuTexture->swapchain->glFramebuffer;
CC_ASSERT(gpuTexture->glTexture || gpuTexture->glRenderbuffer);
if (cacheMap[glResource].empty()) cacheMap[glResource].resize(gpuTexture->mipLevel);
if (!cacheMap[glResource][mipLevel].glFramebuffer) {
GLuint glFramebuffer = 0U;
GL_CHECK(glGenFramebuffers(1, &glFramebuffer));
if (_cache->glDrawFramebuffer != glFramebuffer) {
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, glFramebuffer));
_cache->glDrawFramebuffer = glFramebuffer;
}
const FormatInfo &info = GFX_FORMAT_INFOS[static_cast<uint32_t>(gpuTexture->format)];
GLenum attachment = GL_COLOR_ATTACHMENT0;
if (info.hasStencil) {
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
} else if (info.hasDepth) {
attachment = GL_DEPTH_ATTACHMENT;
}
if (isTexture) {
GL_CHECK(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, gpuTextureView->glTarget, glResource, mipLevel));
} else {
GL_CHECK(glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, glResource));
}
GLenum status;
GL_CHECK(status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
CC_ASSERT_EQ(status, GL_FRAMEBUFFER_COMPLETE);
cacheMap[glResource][mipLevel].glFramebuffer = glFramebuffer;
}
return cacheMap[glResource][mipLevel].glFramebuffer;
}
void onTextureDestroy(const GLES3GPUTexture *gpuTexture) {
bool isTexture = gpuTexture->glTexture;
GLuint glResource = isTexture ? gpuTexture->glTexture : gpuTexture->glRenderbuffer;
auto &cacheMap = isTexture ? _textureMap : _renderbufferMap;
if (cacheMap.count(glResource)) {
for (auto &record : cacheMap[glResource]) {
if (!record.glFramebuffer || record.isExternal) continue;
if (_cache->glDrawFramebuffer == record.glFramebuffer || _cache->glReadFramebuffer == record.glFramebuffer) {
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
_cache->glDrawFramebuffer = _cache->glReadFramebuffer = 0;
}
GL_CHECK(glDeleteFramebuffers(1, &record.glFramebuffer));
}
cacheMap.erase(glResource);
}
}
private:
GLES3GPUStateCache *_cache = nullptr;
struct FramebufferRecord {
GLuint glFramebuffer{0};
bool isExternal{false};
};
using CacheMap = ccstd::unordered_map<GLuint, ccstd::vector<FramebufferRecord>>;
CacheMap _renderbufferMap; // renderbuffer -> mip level -> framebuffer
CacheMap _textureMap; // texture -> mip level -> framebuffer
};
class GLES3GPUFramebufferHub final {
public:
void connect(GLES3GPUTexture *texture, GLES3GPUFramebuffer *framebuffer) {
_framebuffers[texture].push_back(framebuffer);
}
void disengage(GLES3GPUTexture *texture) {
_framebuffers.erase(texture);
}
void disengage(GLES3GPUTexture *texture, GLES3GPUFramebuffer *framebuffer) {
auto &pool = _framebuffers[texture];
pool.erase(std::remove(pool.begin(), pool.end(), framebuffer), pool.end());
}
void update(GLES3GPUTexture *texture);
private:
ccstd::unordered_map<GLES3GPUTexture *, ccstd::vector<GLES3GPUFramebuffer *>> _framebuffers;
};
struct GLES3GPUProgramBinary : public GFXDeviceObject<DefaultDeleter> {
ccstd::string name;
ccstd::hash_t hash = 0;
GLenum format;
std::vector<char> data;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,71 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Buffer.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3InputAssembler.h"
namespace cc {
namespace gfx {
GLES3InputAssembler::GLES3InputAssembler() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3InputAssembler::~GLES3InputAssembler() {
destroy();
}
void GLES3InputAssembler::doInit(const InputAssemblerInfo &info) {
_gpuInputAssembler = ccnew GLES3GPUInputAssembler;
_gpuInputAssembler->attributes = _attributes;
_gpuInputAssembler->gpuVertexBuffers.resize(_vertexBuffers.size());
for (size_t i = 0; i < _gpuInputAssembler->gpuVertexBuffers.size(); ++i) {
auto *vb = static_cast<GLES3Buffer *>(_vertexBuffers[i]);
_gpuInputAssembler->gpuVertexBuffers[i] = vb->gpuBuffer();
}
if (info.indexBuffer) {
_gpuInputAssembler->gpuIndexBuffer = static_cast<GLES3Buffer *>(info.indexBuffer)->gpuBuffer();
}
if (info.indirectBuffer) {
_gpuInputAssembler->gpuIndirectBuffer = static_cast<GLES3Buffer *>(info.indirectBuffer)->gpuBuffer();
}
cmdFuncGLES3CreateInputAssembler(GLES3Device::getInstance(), _gpuInputAssembler);
}
void GLES3InputAssembler::doDestroy() {
if (_gpuInputAssembler) {
cmdFuncGLES3DestroyInputAssembler(GLES3Device::getInstance(), _gpuInputAssembler);
delete _gpuInputAssembler;
_gpuInputAssembler = nullptr;
}
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,51 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXInputAssembler.h"
namespace cc {
namespace gfx {
struct GLES3GPUInputAssembler;
class GLES3CmdDraw;
class CC_GLES3_API GLES3InputAssembler final : public InputAssembler {
public:
GLES3InputAssembler();
~GLES3InputAssembler() override;
inline GLES3GPUInputAssembler *gpuInputAssembler() const { return _gpuInputAssembler; }
protected:
void doInit(const InputAssemblerInfo &info) override;
void doDestroy() override;
GLES3GPUInputAssembler *_gpuInputAssembler = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,215 @@
/****************************************************************************
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3PipelineCache.h"
#include <fstream>
#include "base/BinaryArchive.h"
#include "GLES3GPUObjects.h"
#include "gfx-base/GFXUtil.h"
namespace cc::gfx {
//#define PIPELINE_CACHE_FORCE_INCREMENTAL
#if defined(_WIN32) && !defined(PIPELINE_CACHE_FORCE_INCREMENTAL)
#define PIPELINE_CACHE_FULL
#else
#define PIPELINE_CACHE_INCREMENTAL
#endif
namespace {
const char *fileName = "/pipeline_cache_gles3.bin";
const uint32_t MAGIC = 0x4343474C; // "CCGL"
const uint32_t VERSION = 1;
void saveHeader(BinaryOutputArchive &archive) {
archive.save(MAGIC);
archive.save(VERSION);
}
void saveItem(BinaryOutputArchive &archive, GLES3GPUProgramBinary *binary) {
archive.save(binary->format);
archive.save(static_cast<uint32_t>(binary->name.size()));
archive.save(static_cast<uint32_t>(binary->data.size()));
archive.save(binary->hash);
archive.save(binary->name.data(), static_cast<uint32_t>(binary->name.size()));
archive.save(binary->data.data(), static_cast<uint32_t>(binary->data.size()));
CC_LOG_INFO("Save program cache success, name %s.", binary->name.c_str());
}
} // namespace
GLES3PipelineCache::GLES3PipelineCache() {
_savePath = getPipelineCacheFolder() + fileName;
}
GLES3PipelineCache::~GLES3PipelineCache() { // NOLINT
#ifdef PIPELINE_CACHE_FULL
saveCacheFull();
#endif
}
bool GLES3PipelineCache::loadCache() {
std::ifstream stream(_savePath, std::ios::binary);
if (!stream.is_open()) {
CC_LOG_INFO("Load program cache, no cached files.");
return false;
}
uint32_t magic = 0;
uint32_t version = 0;
BinaryInputArchive archive(stream);
auto loadResult = archive.load(magic);
loadResult &= archive.load(version);
if (magic != MAGIC || version < VERSION) {
// false means invalid cache, need to discard the file content.
return false;
}
uint32_t cachedItemNum = 0;
GLenum format = GL_NONE;
while (loadResult && archive.load(format)) {
++cachedItemNum;
// name length
uint32_t nameLength = 0;
loadResult &= archive.load(nameLength);
// data length
uint32_t dataLength = 0;
loadResult &= archive.load(dataLength);
// skip length if not valid.
if (!checkProgramFormat(format)) {
archive.move(dataLength + nameLength + sizeof(GLES3GPUProgramBinary::hash));
continue;
}
auto *binary = ccnew GLES3GPUProgramBinary();
binary->format = format;
binary->name.resize(nameLength, 0);
binary->data.resize(dataLength, 0);
// hash
loadResult &= archive.load(binary->hash);
// name
loadResult &= archive.load(binary->name.data(), nameLength);
// data
loadResult &= archive.load(binary->data.data(), dataLength);
_programCaches.emplace(binary->name, binary);
}
// If the number of cached items does not equal the number of loaded items, it may be necessary to update the cache.
_dirty = cachedItemNum != _programCaches.size();
CC_LOG_INFO("Load program cache success. records %u, loaded %u", cachedItemNum, _programCaches.size());
return true;
}
void GLES3PipelineCache::saveCacheIncremental(GLES3GPUProgramBinary *binary) {
std::ofstream stream(_savePath, std::ios::binary | std::ios::app);
if (!stream.is_open()) {
CC_LOG_INFO("Save program cache failed.");
return;
}
BinaryOutputArchive archive(stream);
saveItem(archive, binary);
}
void GLES3PipelineCache::saveCacheFull() {
if (!_dirty) {
return;
}
std::ofstream stream(_savePath, std::ios::binary);
if (!stream.is_open()) {
CC_LOG_INFO("Save program cache failed.");
return;
}
BinaryOutputArchive archive(stream);
saveHeader(archive);
for (auto &pair : _programCaches) {
auto &binary = pair.second;
saveItem(archive, binary);
}
_dirty = false;
}
void GLES3PipelineCache::init() {
GLint shaderBinaryFormats = 0;
GL_CHECK(glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &shaderBinaryFormats));
_programBinaryFormats.resize(shaderBinaryFormats);
GL_CHECK(glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, _programBinaryFormats.data()));
bool success = loadCache();
if (!success) {
// discard cache content.
std::ofstream stream(_savePath, std::ios::binary | std::ios::trunc);
#ifdef PIPELINE_CACHE_INCREMENTAL
if (stream.is_open()) {
BinaryOutputArchive archive(stream);
saveHeader(archive);
}
#endif
}
}
void GLES3PipelineCache::addBinary(GLES3GPUProgramBinary *binary) {
_programCaches[binary->name] = binary;
#ifdef PIPELINE_CACHE_INCREMENTAL
saveCacheIncremental(binary);
#endif
_dirty = true;
}
GLES3GPUProgramBinary *GLES3PipelineCache::fetchBinary(const ccstd::string &key, ccstd::hash_t hash) {
auto iter = _programCaches.find(key);
if (iter == _programCaches.end()) {
return nullptr;
}
// if hash not match, re-generate program binary.
if (iter->second->hash != hash) {
_programCaches.erase(iter);
return nullptr;
}
return iter->second;
}
bool GLES3PipelineCache::checkProgramFormat(GLuint format) const {
return std::any_of(_programBinaryFormats.begin(), _programBinaryFormats.end(), [format](const auto &fmt) {
return format == fmt;
});
}
} // namespace cc::gfx

View File

@@ -0,0 +1,63 @@
/****************************************************************************
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3GPUObjects.h"
#include "base/Ptr.h"
#include "base/RefCounted.h"
#include "base/std/container/string.h"
#include "base/std/container/unordered_map.h"
#include "base/std/container/vector.h"
namespace cc {
class BinaryOutputArchive;
}
namespace cc::gfx {
class GLES3GPUShader;
class GLES3PipelineCache : public RefCounted {
public:
GLES3PipelineCache();
~GLES3PipelineCache() override;
void init();
void addBinary(GLES3GPUProgramBinary *binary);
GLES3GPUProgramBinary *fetchBinary(const ccstd::string &key, ccstd::hash_t hash);
bool checkProgramFormat(GLuint format) const;
private:
bool loadCache();
void saveCacheFull();
void saveCacheIncremental(GLES3GPUProgramBinary *binary);
ccstd::vector<GLint> _programBinaryFormats;
ccstd::unordered_map<ccstd::string, IntrusivePtr<GLES3GPUProgramBinary>> _programCaches;
ccstd::string _savePath;
bool _dirty = false;
};
} // namespace cc::gfx

View File

@@ -0,0 +1,76 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3DescriptorSetLayout.h"
#include "GLES3PipelineLayout.h"
#include "base/Utils.h"
namespace cc {
namespace gfx {
GLES3PipelineLayout::GLES3PipelineLayout() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3PipelineLayout::~GLES3PipelineLayout() {
destroy();
}
void GLES3PipelineLayout::doInit(const PipelineLayoutInfo & /*info*/) {
_gpuPipelineLayout = ccnew GLES3GPUPipelineLayout;
uint32_t offset = 0U;
auto &hash = _gpuPipelineLayout->hash;
_gpuPipelineLayout->dynamicOffsetIndices.resize(_setLayouts.size());
for (uint32_t i = 0U; i < _setLayouts.size(); i++) {
DescriptorSetLayout *setLayout = _setLayouts[i];
GLES3GPUDescriptorSetLayout *gpuSetLayout = static_cast<GLES3DescriptorSetLayout *>(setLayout)->gpuDescriptorSetLayout();
uint32_t dynamicCount = utils::toUint(gpuSetLayout->dynamicBindings.size());
ccstd::vector<int> &indices = _gpuPipelineLayout->dynamicOffsetIndices[i];
indices.assign(setLayout->getBindingIndices().size(), -1);
for (uint32_t j = 0U; j < dynamicCount; j++) {
uint32_t binding = gpuSetLayout->dynamicBindings[j];
if (indices[binding] < 0) indices[binding] = static_cast<int32_t>(offset + j);
}
_gpuPipelineLayout->dynamicOffsetOffsets.push_back(static_cast<uint32_t>(offset));
_gpuPipelineLayout->setLayouts.push_back(gpuSetLayout);
offset += dynamicCount;
ccstd::hash_combine(hash, gpuSetLayout->hash);
}
_gpuPipelineLayout->dynamicOffsetOffsets.push_back(static_cast<uint32_t>(offset));
_gpuPipelineLayout->dynamicOffsetCount = static_cast<uint32_t>(offset);
_gpuPipelineLayout->dynamicOffsets.resize(offset);
}
void GLES3PipelineLayout::doDestroy() {
CC_SAFE_DELETE(_gpuPipelineLayout);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXPipelineLayout.h"
namespace cc {
namespace gfx {
struct GLES3GPUPipelineLayout;
class CC_GLES3_API GLES3PipelineLayout final : public PipelineLayout {
public:
GLES3PipelineLayout();
~GLES3PipelineLayout() override;
inline GLES3GPUPipelineLayout *gpuPipelineLayout() const { return _gpuPipelineLayout; }
protected:
void doInit(const PipelineLayoutInfo &info) override;
void doDestroy() override;
GLES3GPUPipelineLayout *_gpuPipelineLayout = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,148 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3PipelineLayout.h"
#include "GLES3PipelineState.h"
#include "GLES3RenderPass.h"
#include "GLES3Shader.h"
namespace cc {
namespace gfx {
const GLenum GLE_S3_PRIMITIVES[] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
GL_LINE_LOOP,
GL_NONE,
GL_NONE,
GL_NONE,
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_NONE,
GL_NONE,
GL_NONE,
GL_NONE,
};
namespace {
void updateGPUShaderSourceByRenderPass(GLES3GPUShader *gpuShader, GLES3GPURenderPass *renderPass, uint32_t subpassIndex) {
auto iter = std::find_if(gpuShader->gpuStages.begin(), gpuShader->gpuStages.end(), [](const GLES3GPUShaderStage &stage) {
return stage.type == ShaderStageFlagBit::FRAGMENT;
});
if (iter == gpuShader->gpuStages.end()) {
return;
}
CC_ASSERT(subpassIndex < renderPass->subpasses.size());
if (renderPass->subpasses.size() <= 1) {
return;
}
bool dsInput{false};
if (renderPass->depthStencil != INVALID_BINDING && !renderPass->subpasses[subpassIndex].inputs.empty()) {
const auto &inputs = renderPass->subpasses[subpassIndex].inputs;
// depth stencil input should always lies at the end of index list.
dsInput = inputs.back() == renderPass->depthStencil;
}
auto &drawBuffers = renderPass->drawBuffers.at(subpassIndex);
ccstd::string::size_type offset = 0;
for (uint32_t i = 0; i < drawBuffers.size(); ++i) {
const char *layoutPrefix = "layout(location = ";
std::stringstream ss1;
ss1 << layoutPrefix << i << ") out";
std::stringstream ss2;
ss2 << layoutPrefix << i << ") inout";
auto &source = iter->source;
auto sIter = source.find(ss1.str(), offset);
if (sIter == std::string::npos) {
sIter = source.find(ss2.str(), offset);
}
if (sIter != std::string::npos) {
auto loc = sIter + strlen(layoutPrefix);
source[loc] = drawBuffers[i] + '0';
offset = loc;
}
}
}
void initGpuShader(GLES3GPUShader *gpuShader, GLES3GPUPipelineLayout *gpuPipelineLayout, GLES3GPURenderPass *renderPass, uint32_t subpassIndex) {
updateGPUShaderSourceByRenderPass(gpuShader, renderPass, subpassIndex);
cmdFuncGLES3CreateShader(GLES3Device::getInstance(), gpuShader, gpuPipelineLayout);
CC_ASSERT(gpuShader->glProgram);
// Clear shader source after they're uploaded to GPU
for (auto &stage : gpuShader->gpuStages) {
stage.source.clear();
stage.source.shrink_to_fit();
}
}
} // namespace
GLES3PipelineState::GLES3PipelineState() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3PipelineState::~GLES3PipelineState() {
destroy();
}
void GLES3PipelineState::doInit(const PipelineStateInfo & /*info*/) {
_gpuPipelineState = ccnew GLES3GPUPipelineState;
_gpuPipelineState->glPrimitive = GLE_S3_PRIMITIVES[static_cast<int>(_primitive)];
_gpuPipelineState->rs = _rasterizerState;
_gpuPipelineState->dss = _depthStencilState;
_gpuPipelineState->bs = _blendState;
_gpuPipelineState->gpuPipelineLayout = static_cast<GLES3PipelineLayout *>(_pipelineLayout)->gpuPipelineLayout();
_gpuPipelineState->gpuShader = static_cast<GLES3Shader *>(_shader)->gpuShader();
if (_renderPass) _gpuPipelineState->gpuRenderPass = static_cast<GLES3RenderPass *>(_renderPass)->gpuRenderPass();
if (_gpuPipelineState->gpuShader->glProgram == 0) {
initGpuShader(_gpuPipelineState->gpuShader, _gpuPipelineState->gpuPipelineLayout, _gpuPipelineState->gpuRenderPass, _subpass);
}
if (_renderPass) _gpuPipelineState->gpuRenderPass = static_cast<GLES3RenderPass *>(_renderPass)->gpuRenderPass();
for (uint32_t i = 0; i < 31; i++) {
if (static_cast<uint32_t>(_dynamicStates) & (1 << i)) {
_gpuPipelineState->dynamicStates.push_back(static_cast<DynamicStateFlagBit>(1 << i));
}
}
}
void GLES3PipelineState::doDestroy() {
CC_SAFE_DELETE(_gpuPipelineState);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXPipelineState.h"
namespace cc {
namespace gfx {
struct GLES3GPUPipelineState;
class CC_GLES3_API GLES3PipelineState final : public PipelineState {
public:
GLES3PipelineState();
~GLES3PipelineState() override;
inline GLES3GPUPipelineState *gpuPipelineState() const { return _gpuPipelineState; }
protected:
void doInit(const PipelineStateInfo &info) override;
void doDestroy() override;
GLES3GPUPipelineState *_gpuPipelineState = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,301 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Buffer.h"
#include "GLES3Commands.h"
#include "GLES3DescriptorSet.h"
#include "GLES3Device.h"
#include "GLES3Framebuffer.h"
#include "GLES3InputAssembler.h"
#include "GLES3PipelineState.h"
#include "GLES3PrimaryCommandBuffer.h"
#include "GLES3QueryPool.h"
#include "GLES3RenderPass.h"
#include "GLES3Texture.h"
#include "profiler/Profiler.h"
#include "states/GLES3GeneralBarrier.h"
namespace cc {
namespace gfx {
GLES3PrimaryCommandBuffer::~GLES3PrimaryCommandBuffer() {
destroy();
}
void GLES3PrimaryCommandBuffer::begin(RenderPass * /*renderPass*/, uint32_t /*subpass*/, Framebuffer * /*frameBuffer*/) {
_curGPUPipelineState = nullptr;
_curGPUInputAssember = nullptr;
_curGPUDescriptorSets.assign(_curGPUDescriptorSets.size(), nullptr);
_numDrawCalls = 0;
_numInstances = 0;
_numTriangles = 0;
}
void GLES3PrimaryCommandBuffer::end() {
if (_isStateInvalid) {
bindStates();
}
}
void GLES3PrimaryCommandBuffer::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const * /*secondaryCBs*/, uint32_t /*secondaryCBCount*/) {
_curSubpassIdx = 0U;
auto *gpuRenderPass = static_cast<GLES3RenderPass *>(renderPass)->gpuRenderPass();
GLES3GPUFramebuffer *gpuFramebuffer = static_cast<GLES3Framebuffer *>(fbo)->gpuFBO();
cmdFuncGLES3BeginRenderPass(GLES3Device::getInstance(), gpuRenderPass, gpuFramebuffer, &renderArea, colors, depth, stencil);
_curDynamicStates.viewport = {renderArea.x, renderArea.y, renderArea.width, renderArea.height};
_curDynamicStates.scissor = renderArea;
}
void GLES3PrimaryCommandBuffer::endRenderPass() {
cmdFuncGLES3EndRenderPass(GLES3Device::getInstance());
}
void GLES3PrimaryCommandBuffer::nextSubpass() {
++_curSubpassIdx;
}
void GLES3PrimaryCommandBuffer::insertMarker(const MarkerInfo &marker) {
cmdFuncGLES3InsertMarker(GLES3Device::getInstance(), marker.name.size(), marker.name.data());
}
void GLES3PrimaryCommandBuffer::beginMarker(const MarkerInfo &marker) {
cmdFuncGLES3PushGroupMarker(GLES3Device::getInstance(), marker.name.size(), marker.name.data());
}
void GLES3PrimaryCommandBuffer::endMarker() {
cmdFuncGLES3PopGroupMarker(GLES3Device::getInstance());
}
void GLES3PrimaryCommandBuffer::draw(const DrawInfo &info) {
CC_PROFILE(GLES3PrimaryCommandBufferDraw);
if (_isStateInvalid) {
bindStates();
}
cmdFuncGLES3Draw(GLES3Device::getInstance(), info);
++_numDrawCalls;
_numInstances += info.instanceCount;
if (_curGPUPipelineState) {
uint32_t indexCount = info.indexCount ? info.indexCount : info.vertexCount;
switch (_curGPUPipelineState->glPrimitive) {
case GL_TRIANGLES: {
_numTriangles += indexCount / 3 * std::max(info.instanceCount, 1U);
break;
}
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN: {
_numTriangles += (indexCount - 2) * std::max(info.instanceCount, 1U);
break;
}
default:
break;
}
}
}
void GLES3PrimaryCommandBuffer::setViewport(const Viewport &vp) {
auto *cache = GLES3Device::getInstance()->stateCache();
if (cache->viewport != vp) {
cache->viewport = vp;
GL_CHECK(glViewport(vp.left, vp.top, vp.width, vp.height));
}
}
void GLES3PrimaryCommandBuffer::setScissor(const Rect &rect) {
auto *cache = GLES3Device::getInstance()->stateCache();
if (cache->scissor != rect) {
cache->scissor = rect;
GL_CHECK(glScissor(rect.x, rect.y, rect.width, rect.height));
}
}
void GLES3PrimaryCommandBuffer::updateBuffer(Buffer *buff, const void *data, uint32_t size) {
GLES3GPUBuffer *gpuBuffer = static_cast<GLES3Buffer *>(buff)->gpuBuffer();
if (gpuBuffer) {
cmdFuncGLES3UpdateBuffer(GLES3Device::getInstance(), gpuBuffer, data, 0U, size);
}
}
void GLES3PrimaryCommandBuffer::copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) {
GLES3GPUTexture *gpuTexture = static_cast<GLES3Texture *>(texture)->gpuTexture();
if (gpuTexture) {
cmdFuncGLES3CopyBuffersToTexture(GLES3Device::getInstance(), buffers, gpuTexture, regions, count);
}
}
void GLES3PrimaryCommandBuffer::resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
copyTexture(srcTexture, dstTexture, regions, count);
}
void GLES3PrimaryCommandBuffer::copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
GLES3GPUTextureView *gpuTextureSrc = nullptr;
GLES3GPUTextureView *gpuTextureDst = nullptr;
if (srcTexture) gpuTextureSrc = static_cast<GLES3Texture *>(srcTexture)->gpuTextureView();
if (dstTexture) gpuTextureDst = static_cast<GLES3Texture *>(dstTexture)->gpuTextureView();
ccstd::vector<TextureBlit> blitRegions(count);
for (uint32_t i = 0; i < count; ++i) {
auto &blit = blitRegions[i];
const auto &copy = regions[i];
blit.srcSubres = copy.srcSubres;
blit.dstSubres = copy.dstSubres;
blit.srcOffset = copy.srcOffset;
blit.dstOffset = copy.dstOffset;
blit.srcExtent = copy.extent;
blit.dstExtent = copy.extent;
}
cmdFuncGLES3BlitTexture(GLES3Device::getInstance(), gpuTextureSrc, gpuTextureDst, blitRegions.data(), count, Filter::POINT);
}
void GLES3PrimaryCommandBuffer::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) {
GLES3GPUTextureView *gpuTextureSrc = nullptr;
GLES3GPUTextureView *gpuTextureDst = nullptr;
if (srcTexture) gpuTextureSrc = static_cast<GLES3Texture *>(srcTexture)->gpuTextureView();
if (dstTexture) gpuTextureDst = static_cast<GLES3Texture *>(dstTexture)->gpuTextureView();
cmdFuncGLES3BlitTexture(GLES3Device::getInstance(), gpuTextureSrc, gpuTextureDst, regions, count, filter);
}
void GLES3PrimaryCommandBuffer::beginQuery(QueryPool *queryPool, uint32_t id) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
cmdFuncGLES3Query(GLES3Device::getInstance(), gles3QueryPool, GLES3QueryType::BEGIN, id);
}
void GLES3PrimaryCommandBuffer::endQuery(QueryPool *queryPool, uint32_t id) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
cmdFuncGLES3Query(GLES3Device::getInstance(), gles3QueryPool, GLES3QueryType::END, id);
}
void GLES3PrimaryCommandBuffer::resetQueryPool(QueryPool *queryPool) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
cmdFuncGLES3Query(GLES3Device::getInstance(), gles3QueryPool, GLES3QueryType::RESET, 0);
}
void GLES3PrimaryCommandBuffer::getQueryPoolResults(QueryPool *queryPool) {
auto *gles3QueryPool = static_cast<GLES3QueryPool *>(queryPool);
cmdFuncGLES3Query(GLES3Device::getInstance(), gles3QueryPool, GLES3QueryType::GET_RESULTS, 0);
}
void GLES3PrimaryCommandBuffer::execute(CommandBuffer *const *cmdBuffs, uint32_t count) {
for (uint32_t i = 0; i < count; ++i) {
auto *cmdBuff = static_cast<GLES3PrimaryCommandBuffer *>(cmdBuffs[i]);
if (!cmdBuff->_pendingPackages.empty()) {
GLES3CmdPackage *cmdPackage = cmdBuff->_pendingPackages.front();
cmdFuncGLES3ExecuteCmds(GLES3Device::getInstance(), cmdPackage);
cmdBuff->_pendingPackages.pop();
cmdBuff->_freePackages.push(cmdPackage);
cmdBuff->_cmdAllocator->clearCmds(cmdPackage);
cmdBuff->_cmdAllocator->reset();
}
_numDrawCalls += cmdBuff->_numDrawCalls;
_numInstances += cmdBuff->_numInstances;
_numTriangles += cmdBuff->_numTriangles;
}
}
void GLES3PrimaryCommandBuffer::bindStates() {
if (_curGPUPipelineState) {
ccstd::vector<uint32_t> &dynamicOffsetOffsets = _curGPUPipelineState->gpuPipelineLayout->dynamicOffsetOffsets;
ccstd::vector<uint32_t> &dynamicOffsets = _curGPUPipelineState->gpuPipelineLayout->dynamicOffsets;
for (size_t i = 0U, len = dynamicOffsetOffsets.size() - 1; i < len; i++) {
size_t count = dynamicOffsetOffsets[i + 1] - dynamicOffsetOffsets[i];
// CC_ASSERT(_curDynamicOffsets[i].size() >= count);
count = std::min(count, _curDynamicOffsets[i].size());
if (count) memcpy(&dynamicOffsets[dynamicOffsetOffsets[i]], _curDynamicOffsets[i].data(), count * sizeof(uint32_t));
}
cmdFuncGLES3BindState(GLES3Device::getInstance(), _curGPUPipelineState, _curGPUInputAssember,
_curGPUDescriptorSets.data(), dynamicOffsets.data(), &_curDynamicStates);
}
_isStateInvalid = false;
}
void GLES3PrimaryCommandBuffer::dispatch(const DispatchInfo &info) {
if (_isStateInvalid) {
bindStates();
}
GLES3GPUDispatchInfo gpuInfo;
if (info.indirectBuffer) {
gpuInfo.indirectBuffer = static_cast<GLES3Buffer *>(info.indirectBuffer)->gpuBuffer();
gpuInfo.indirectOffset = info.indirectOffset;
} else {
gpuInfo.groupCountX = info.groupCountX;
gpuInfo.groupCountY = info.groupCountY;
gpuInfo.groupCountZ = info.groupCountZ;
}
cmdFuncGLES3Dispatch(GLES3Device::getInstance(), gpuInfo);
}
void GLES3PrimaryCommandBuffer::pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const * /*buffers*/, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const * /*textures*/, uint32_t textureBarrierCount) {
if (!barrier && !bufferBarrierCount && !textureBarrierCount) return;
GLuint glBarriers{0};
GLuint glBarriersByRegion{0};
if (barrier) {
GLES3GPUGeneralBarrier genBarrier = *(static_cast<const GLES3GeneralBarrier *>(barrier)->gpuBarrier());
glBarriers |= genBarrier.glBarriers;
glBarriersByRegion |= genBarrier.glBarriersByRegion;
}
auto fullfill = [&glBarriers, &glBarriersByRegion](auto *barriers, uint32_t count) {
for (size_t i = 0; i < count; ++i) {
GLES3GPUGeneralBarrier barrier{
barriers[i]->getInfo().prevAccesses,
barriers[i]->getInfo().nextAccesses,
0,
0,
};
completeBarrier(&barrier);
glBarriers |= barrier.glBarriers;
glBarriersByRegion |= barrier.glBarriersByRegion;
}
};
fullfill(bufferBarriers, bufferBarrierCount);
fullfill(textureBarriers, textureBarrierCount);
cmdFuncGLES3MemoryBarrier(GLES3Device::getInstance(), glBarriers, glBarriersByRegion);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,70 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3CommandBuffer.h"
namespace cc {
namespace gfx {
class CC_GLES3_API GLES3PrimaryCommandBuffer final : public GLES3CommandBuffer {
public:
GLES3PrimaryCommandBuffer() = default;
~GLES3PrimaryCommandBuffer() override;
void begin(RenderPass *renderPass, uint32_t subpass, Framebuffer *frameBuffer) override;
void end() override;
void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const *secondaryCBs, uint32_t secondaryCBCount) override;
void endRenderPass() override;
void nextSubpass() override;
void insertMarker(const MarkerInfo &marker) override;
void beginMarker(const MarkerInfo &marker) override;
void endMarker() override;
void draw(const DrawInfo &info) override;
void setViewport(const Viewport &vp) override;
void setScissor(const Rect &rect) override;
void updateBuffer(Buffer *buff, const void *data, uint32_t size) override;
void copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) override;
void execute(CommandBuffer *const *cmdBuffs, uint32_t count) override;
void dispatch(const DispatchInfo &info) override;
void pipelineBarrier(const GeneralBarrier *barrier, const BufferBarrier *const *bufferBarriers, const Buffer *const * /*buffers*/, uint32_t bufferBarrierCount, const TextureBarrier *const *textureBarriers, const Texture *const * /*textures*/, uint32_t textureBarrierCount) override;
void blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) override;
void copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
void resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
void beginQuery(QueryPool *queryPool, uint32_t id) override;
void endQuery(QueryPool *queryPool, uint32_t id) override;
void resetQueryPool(QueryPool *queryPool) override;
protected:
friend class GLES3Queue;
friend class GLES3QueryPool;
void getQueryPoolResults(QueryPool *query) override;
void bindStates() override;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,63 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3QueryPool.h"
#include "GLES3CommandBuffer.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
namespace cc {
namespace gfx {
GLES3QueryPool::GLES3QueryPool() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3QueryPool::~GLES3QueryPool() {
destroy();
}
void GLES3QueryPool::doInit(const QueryPoolInfo & /*info*/) {
GLES3Device *device = GLES3Device::getInstance();
if (device->getCapabilities().supportQuery) {
_gpuQueryPool = ccnew GLES3GPUQueryPool;
_gpuQueryPool->type = _type;
_gpuQueryPool->maxQueryObjects = _maxQueryObjects;
_gpuQueryPool->forceWait = _forceWait;
_gpuQueryPool->glQueryIds.resize(_maxQueryObjects, 0U);
cmdFuncGLES3CreateQueryPool(device, _gpuQueryPool);
}
}
void GLES3QueryPool::doDestroy() {
if (_gpuQueryPool) {
cmdFuncGLES3DestroyQueryPool(GLES3Device::getInstance(), _gpuQueryPool);
delete _gpuQueryPool;
_gpuQueryPool = nullptr;
}
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,59 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXQueryPool.h"
namespace cc {
namespace gfx {
class GLES3GPUQueryPool;
class CC_GLES3_API GLES3QueryPool final : public QueryPool {
public:
GLES3QueryPool();
~GLES3QueryPool() override;
inline GLES3GPUQueryPool *gpuQueryPool() const { return _gpuQueryPool; }
inline uint32_t getIdCount() const { return static_cast<uint32_t>(_ids.size()); }
inline void clearId() { _ids.clear(); }
inline void addId(uint32_t id) { _ids.push_back(id); }
inline uint32_t getId(uint32_t index) const { return _ids[index]; }
inline std::mutex &getMutex() { return _mutex; }
inline void setResults(ccstd::unordered_map<uint32_t, uint64_t> &&results) { _results = results; }
protected:
friend class GLES3CommandBuffer;
void doInit(const QueryPoolInfo &info) override;
void doDestroy() override;
GLES3GPUQueryPool *_gpuQueryPool = nullptr;
ccstd::vector<uint32_t> _ids;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,71 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3CommandBuffer.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3Queue.h"
namespace cc {
namespace gfx {
GLES3Queue::GLES3Queue() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3Queue::~GLES3Queue() {
destroy();
}
void GLES3Queue::doInit(const QueueInfo &info) {
}
void GLES3Queue::doDestroy() {
}
void GLES3Queue::submit(CommandBuffer *const *cmdBuffs, uint32_t count) {
for (uint32_t i = 0; i < count; ++i) {
auto *cmdBuff = static_cast<GLES3CommandBuffer *>(cmdBuffs[i]);
if (!cmdBuff->_pendingPackages.empty()) {
GLES3CmdPackage *cmdPackage = cmdBuff->_pendingPackages.front();
cmdFuncGLES3ExecuteCmds(GLES3Device::getInstance(), cmdPackage);
cmdBuff->_pendingPackages.pop();
cmdBuff->_freePackages.push(cmdPackage);
cmdBuff->_cmdAllocator->clearCmds(cmdPackage);
cmdBuff->_cmdAllocator->reset();
}
_numDrawCalls += cmdBuff->_numDrawCalls;
_numInstances += cmdBuff->_numInstances;
_numTriangles += cmdBuff->_numTriangles;
}
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,52 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXQueue.h"
namespace cc {
namespace gfx {
class CC_GLES3_API GLES3Queue final : public Queue {
public:
GLES3Queue();
~GLES3Queue() override;
void submit(CommandBuffer *const *cmdBuffs, uint32_t count) override;
protected:
friend class GLES3Device;
void doInit(const QueueInfo &info) override;
void doDestroy() override;
uint32_t _numDrawCalls = 0;
uint32_t _numInstances = 0;
uint32_t _numTriangles = 0;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,90 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3RenderPass.h"
#include "gfx-base/GFXDef-common.h"
namespace cc {
namespace gfx {
GLES3RenderPass::GLES3RenderPass() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3RenderPass::~GLES3RenderPass() {
destroy();
}
void GLES3RenderPass::doInit(const RenderPassInfo & /*info*/) {
_gpuRenderPass = ccnew GLES3GPURenderPass;
_gpuRenderPass->colorAttachments = _colorAttachments;
_gpuRenderPass->depthStencilAttachment = _depthStencilAttachment;
_gpuRenderPass->depthStencilResolveAttachment = _depthStencilResolveAttachment;
_gpuRenderPass->subpasses = _subpasses;
_gpuRenderPass->dependencies = _dependencies;
// assign a dummy subpass if not specified
uint32_t colorCount = utils::toUint(_gpuRenderPass->colorAttachments.size());
if (_gpuRenderPass->subpasses.empty()) {
_gpuRenderPass->subpasses.emplace_back();
auto &subpass = _gpuRenderPass->subpasses.back();
subpass.colors.resize(_colorAttachments.size());
for (uint32_t i = 0U; i < _colorAttachments.size(); ++i) {
subpass.colors[i] = i;
}
if (_depthStencilAttachment.format != Format::UNKNOWN) {
subpass.depthStencil = colorCount;
}
if (_depthStencilResolveAttachment.format != Format::UNKNOWN) {
subpass.depthStencil = colorCount + 1;
}
} else {
// unify depth stencil index
for (auto &subpass : _gpuRenderPass->subpasses) {
if (subpass.depthStencil != INVALID_BINDING && subpass.depthStencil >= colorCount) {
subpass.depthStencil = colorCount;
}
if (subpass.depthStencilResolve != INVALID_BINDING && subpass.depthStencil >= colorCount) {
subpass.depthStencilResolve = colorCount + 1;
}
}
}
cmdFuncGLES3CreateRenderPass(GLES3Device::getInstance(), _gpuRenderPass);
}
void GLES3RenderPass::doDestroy() {
if (_gpuRenderPass) {
cmdFuncGLES3DestroyRenderPass(GLES3Device::getInstance(), _gpuRenderPass);
delete _gpuRenderPass;
_gpuRenderPass = nullptr;
}
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXRenderPass.h"
namespace cc {
namespace gfx {
struct GLES3GPURenderPass;
class CC_GLES3_API GLES3RenderPass final : public RenderPass {
public:
GLES3RenderPass();
~GLES3RenderPass() override;
inline GLES3GPURenderPass *gpuRenderPass() const { return _gpuRenderPass; }
protected:
void doInit(const RenderPassInfo &info) override;
void doDestroy() override;
GLES3GPURenderPass *_gpuRenderPass = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,78 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3Shader.h"
#include "base/std/hash/hash_fwd.hpp"
namespace cc {
namespace gfx {
GLES3Shader::GLES3Shader() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3Shader::~GLES3Shader() {
destroy();
}
GLES3GPUShader *GLES3Shader::gpuShader() const {
return _gpuShader;
}
void GLES3Shader::doInit(const ShaderInfo & /*info*/) {
_gpuShader = ccnew GLES3GPUShader;
CC_ASSERT(!_gpuShader->glProgram);
_gpuShader->name = _name;
_gpuShader->blocks = _blocks;
_gpuShader->buffers = _buffers;
_gpuShader->samplerTextures = _samplerTextures;
_gpuShader->samplers = _samplers;
_gpuShader->textures = _textures;
_gpuShader->images = _images;
_gpuShader->subpassInputs = _subpassInputs;
_gpuShader->hash = _hash;
for (const auto &stage : _stages) {
GLES3GPUShaderStage gpuShaderStage = {stage.stage, stage.source};
_gpuShader->gpuStages.emplace_back(std::move(gpuShaderStage));
}
for (auto &stage : _stages) {
stage.source.clear();
stage.source.shrink_to_fit();
}
}
void GLES3Shader::doDestroy() {
if (_gpuShader) {
cmdFuncGLES3DestroyShader(GLES3Device::getInstance(), _gpuShader);
delete _gpuShader;
_gpuShader = nullptr;
}
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXShader.h"
namespace cc {
namespace gfx {
struct GLES3GPUShader;
class CC_GLES3_API GLES3Shader final : public Shader {
public:
GLES3Shader();
~GLES3Shader() override;
GLES3GPUShader *gpuShader() const;
protected:
void doInit(const ShaderInfo &info) override;
void doDestroy() override;
GLES3GPUShader *_gpuShader = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,65 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "base/Log.h"
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
#if defined(CC_STATIC)
#define CC_GLES3_API
#else
#ifdef CC_GLES3_EXPORTS
#define CC_GLES3_API __declspec(dllexport)
#else
#define CC_GLES3_API __declspec(dllimport)
#endif
#endif
#else
#define CC_GLES3_API
#endif
#if CC_DEBUG > 0
#define GL_CHECK(x) \
do { \
x; \
GLenum err = glGetError(); \
if (err != GL_NO_ERROR) { \
CC_LOG_ERROR("%s returned GL error: 0x%x", #x, err); \
CC_ABORT(); \
} \
} while (0)
#define EGL_CHECK(x) \
do { \
x; \
EGLint err = eglGetError(); \
if (err != EGL_SUCCESS) { \
CC_LOG_ERROR("%s returned EGL error: 0x%x", #x, err); \
CC_ABORT(); \
} \
} while (0)
#else
#define GL_CHECK(x) x
#define EGL_CHECK(x) x
#endif

View File

@@ -0,0 +1,243 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "application/ApplicationManager.h"
#include "platform/interfaces/modules/IXRInterface.h"
#include "GLES3Device.h"
#include "GLES3GPUObjects.h"
#include "GLES3Swapchain.h"
#include "GLES3Texture.h"
#if CC_SWAPPY_ENABLED
#include "platform/android/AndroidPlatform.h"
#include "swappy/swappyGL.h"
#endif
#if (CC_PLATFORM == CC_PLATFORM_ANDROID)
#include "android/native_window.h"
#elif CC_PLATFORM == CC_PLATFORM_OHOS
#include <native_layer.h>
#include <native_layer_jni.h>
#endif
namespace cc {
namespace gfx {
GLES3Swapchain::GLES3Swapchain() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3Swapchain::~GLES3Swapchain() {
destroy();
}
void GLES3Swapchain::doInit(const SwapchainInfo &info) {
_xr = CC_GET_XR_INTERFACE();
if (_xr) {
_xr->updateXRSwapchainTypedID(getTypedID());
}
auto width = static_cast<int32_t>(info.width);
auto height = static_cast<int32_t>(info.height);
const auto *context = GLES3Device::getInstance()->context();
_gpuSwapchain = ccnew GLES3GPUSwapchain;
#if CC_PLATFORM == CC_PLATFORM_LINUX
auto window = reinterpret_cast<EGLNativeWindowType>(info.windowHandle);
#else
auto *window = reinterpret_cast<EGLNativeWindowType>(info.windowHandle);
#endif
#if CC_PLATFORM == CC_PLATFORM_ANDROID || CC_PLATFORM == CC_PLATFORM_OHOS
EGLint nFmt;
if (eglGetConfigAttrib(context->eglDisplay, context->eglConfig, EGL_NATIVE_VISUAL_ID, &nFmt) == EGL_FALSE) {
CC_LOG_ERROR("Getting configuration attributes failed.");
return;
}
#if CC_SWAPPY_ENABLED
bool enableSwappy = true;
auto *platform = static_cast<AndroidPlatform *>(cc::BasePlatform::getPlatform());
enableSwappy &= SwappyGL_init(static_cast<JNIEnv *>(platform->getEnv()), static_cast<jobject>(platform->getActivity()));
int32_t fps = cc::BasePlatform::getPlatform()->getFps();
if (enableSwappy) {
if (!fps)
SwappyGL_setSwapIntervalNS(SWAPPY_SWAP_60FPS);
else
SwappyGL_setSwapIntervalNS(1000000000L / fps); //ns
enableSwappy &= SwappyGL_setWindow(window);
_gpuSwapchain->swappyEnabled = enableSwappy;
} else {
CC_LOG_ERROR("Failed to enable Swappy in current GL swapchain, fallback instead.");
}
#endif
if (_xr) {
width = _xr->getXRConfig(xr::XRConfigKey::SWAPCHAIN_WIDTH).getInt();
height = _xr->getXRConfig(xr::XRConfigKey::SWAPCHAIN_HEIGHT).getInt();
}
#if CC_PLATFORM == CC_PLATFORM_ANDROID
ANativeWindow_setBuffersGeometry(window, width, height, nFmt);
#elif CC_PLATFORM == CC_PLATFORM_OHOS
NativeLayerHandle(window, NativeLayerOps::SET_WIDTH_AND_HEIGHT, width, height);
NativeLayerHandle(window, NativeLayerOps::SET_FORMAT, nFmt);
#endif
#endif
EGLSurfaceType surfaceType = _xr ? _xr->acquireEGLSurfaceType(getTypedID()) : EGLSurfaceType::WINDOW;
if (surfaceType == EGLSurfaceType::PBUFFER) {
EGLint pbufferAttribs[]{
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE};
EGL_CHECK(_gpuSwapchain->eglSurface = eglCreatePbufferSurface(context->eglDisplay, context->eglConfig, pbufferAttribs));
} else if (surfaceType == EGLSurfaceType::WINDOW) {
EGL_CHECK(_gpuSwapchain->eglSurface = eglCreateWindowSurface(context->eglDisplay, context->eglConfig, window, nullptr));
if (_gpuSwapchain->eglSurface == EGL_NO_SURFACE) {
CC_LOG_ERROR("Create window surface failed.");
return;
}
}
if (_xr) {
GLES3Device::getInstance()->context()->makeCurrent(_gpuSwapchain, _gpuSwapchain);
_gpuSwapchain->isXR = true;
}
switch (_vsyncMode) {
case VsyncMode::OFF: _gpuSwapchain->eglSwapInterval = 0; break;
case VsyncMode::ON:
case VsyncMode::RELAXED: _gpuSwapchain->eglSwapInterval = 1; break;
case VsyncMode::MAILBOX: _gpuSwapchain->eglSwapInterval = 0; break;
case VsyncMode::HALF: _gpuSwapchain->eglSwapInterval = 2; break;
default: break;
}
///////////////////// Texture Creation /////////////////////
_colorTexture = ccnew GLES3Texture;
_depthStencilTexture = ccnew GLES3Texture;
SwapchainTextureInfo textureInfo;
textureInfo.swapchain = this;
textureInfo.format = Format::RGBA8;
textureInfo.width = width;
textureInfo.height = height;
initTexture(textureInfo, _colorTexture);
textureInfo.format = Format::DEPTH_STENCIL;
initTexture(textureInfo, _depthStencilTexture);
_gpuSwapchain->gpuColorTexture = static_cast<GLES3Texture *>(_colorTexture.get())->gpuTexture();
}
void GLES3Swapchain::doDestroy() {
if (!_gpuSwapchain) return;
#if CC_SWAPPY_ENABLED
if (_gpuSwapchain->swappyEnabled) {
SwappyGL_destroy();
}
#endif
CC_SAFE_DESTROY(_depthStencilTexture)
CC_SAFE_DESTROY(_colorTexture)
doDestroySurface();
CC_SAFE_DELETE(_gpuSwapchain);
}
void GLES3Swapchain::doResize(uint32_t width, uint32_t height, SurfaceTransform /*transform*/) {
_colorTexture->resize(width, height);
_depthStencilTexture->resize(width, height);
if (_windowHandle) {
doCreateSurface(_windowHandle);
}
}
void GLES3Swapchain::doDestroySurface() {
if (_gpuSwapchain->eglSurface != EGL_NO_SURFACE) {
auto *context = GLES3Device::getInstance()->context();
eglDestroySurface(context->eglDisplay, _gpuSwapchain->eglSurface);
_gpuSwapchain->eglSurface = EGL_NO_SURFACE;
context->bindContext(true);
}
}
void GLES3Swapchain::doCreateSurface(void *windowHandle) {
auto *context = GLES3Device::getInstance()->context();
#if CC_PLATFORM == CC_PLATFORM_LINUX
auto window = reinterpret_cast<EGLNativeWindowType>(windowHandle);
#else
auto *window = reinterpret_cast<EGLNativeWindowType>(windowHandle);
#endif
EGLint nFmt = 0;
if (eglGetConfigAttrib(context->eglDisplay, context->eglConfig, EGL_NATIVE_VISUAL_ID, &nFmt) == EGL_FALSE) {
CC_LOG_ERROR("Getting configuration attributes failed.");
return;
}
auto width = static_cast<int>(_colorTexture->getWidth());
auto height = static_cast<int>(_colorTexture->getHeight());
CC_UNUSED_PARAM(width);
CC_UNUSED_PARAM(height);
#if CC_SWAPPY_ENABLED
if (_gpuSwapchain->swappyEnabled) {
_gpuSwapchain->swappyEnabled &= SwappyGL_setWindow(window);
}
#endif
#if CC_PLATFORM == CC_PLATFORM_ANDROID
ANativeWindow_setBuffersGeometry(window, width, height, nFmt);
#elif CC_PLATFORM == CC_PLATFORM_OHOS
NativeLayerHandle(window, NativeLayerOps::SET_WIDTH_AND_HEIGHT, width, height);
NativeLayerHandle(window, SET_FORMAT, nFmt);
#endif
if (_gpuSwapchain->eglSurface == EGL_NO_SURFACE) {
IXRInterface *xr = CC_GET_XR_INTERFACE();
EGLSurfaceType surfaceType = xr ? xr->acquireEGLSurfaceType(getTypedID()) : EGLSurfaceType::WINDOW;
if (surfaceType == EGLSurfaceType::PBUFFER) {
EGLint pbufferAttribs[]{
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE};
EGL_CHECK(_gpuSwapchain->eglSurface = eglCreatePbufferSurface(context->eglDisplay, context->eglConfig, pbufferAttribs));
} else if (surfaceType == EGLSurfaceType::WINDOW) {
EGL_CHECK(_gpuSwapchain->eglSurface = eglCreateWindowSurface(context->eglDisplay, context->eglConfig, window, nullptr));
if (_gpuSwapchain->eglSurface == EGL_NO_SURFACE) {
CC_LOG_ERROR("Recreate window surface failed.");
return;
}
}
}
context->makeCurrent(_gpuSwapchain, _gpuSwapchain);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,55 @@
/****************************************************************************
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXSwapchain.h"
namespace cc {
class IXRInterface;
namespace gfx {
struct GLES3GPUSwapchain;
class CC_GLES3_API GLES3Swapchain final : public Swapchain {
public:
GLES3Swapchain();
~GLES3Swapchain() override;
inline GLES3GPUSwapchain *gpuSwapchain() const { return _gpuSwapchain; }
protected:
void doInit(const SwapchainInfo &info) override;
void doDestroy() override;
void doResize(uint32_t width, uint32_t height, SurfaceTransform transform) override;
void doDestroySurface() override;
void doCreateSurface(void *windowHandle) override;
GLES3GPUSwapchain *_gpuSwapchain{nullptr};
IXRInterface *_xr{nullptr};
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,183 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Std.h"
#include "GLES3Commands.h"
#include "GLES3Device.h"
#include "GLES3Swapchain.h"
#include "GLES3Texture.h"
#include "base/Macros.h"
#include "profiler/Profiler.h"
namespace cc {
namespace gfx {
GLES3Texture::GLES3Texture() {
_typedID = generateObjectID<decltype(this)>();
}
GLES3Texture::~GLES3Texture() {
destroy();
}
void GLES3Texture::doInit(const TextureInfo & /*info*/) {
_gpuTexture = ccnew GLES3GPUTexture;
_gpuTexture->type = _info.type;
_gpuTexture->format = _info.format;
_gpuTexture->usage = _info.usage;
_gpuTexture->width = _info.width;
_gpuTexture->height = _info.height;
_gpuTexture->depth = _info.depth;
_gpuTexture->arrayLayer = _info.layerCount;
_gpuTexture->mipLevel = _info.levelCount;
_gpuTexture->glSamples = static_cast<GLint>(_info.samples);
_gpuTexture->flags = _info.flags;
_gpuTexture->size = _size;
_gpuTexture->isPowerOf2 = math::isPowerOfTwo(_info.width) && math::isPowerOfTwo(_info.height);
bool hasExternalFlag = hasFlag(_gpuTexture->flags, TextureFlagBit::EXTERNAL_NORMAL) ||
hasFlag(_gpuTexture->flags, TextureFlagBit::EXTERNAL_OES);
if (_info.externalRes && !hasExternalFlag) {
// compatibility
_gpuTexture->flags = _gpuTexture->flags | TextureFlagBit::EXTERNAL_OES;
hasExternalFlag = true;
}
if (hasExternalFlag) {
_gpuTexture->glTexture = static_cast<GLuint>(reinterpret_cast<size_t>(_info.externalRes));
}
cmdFuncGLES3CreateTexture(GLES3Device::getInstance(), _gpuTexture);
if (_gpuTexture->memoryAllocated) {
GLES3Device::getInstance()->getMemoryStatus().textureSize += _size;
CC_PROFILE_MEMORY_INC(Texture, _size);
}
_gpuTextureView = ccnew GLES3GPUTextureView;
createTextureView();
}
void GLES3Texture::doInit(const TextureViewInfo & /*info*/) {
_gpuTexture = static_cast<GLES3Texture *>(_viewInfo.texture)->gpuTexture();
CC_ASSERT(_viewInfo.texture->getFormat() == _viewInfo.format);
_gpuTextureView = ccnew GLES3GPUTextureView;
createTextureView();
}
void GLES3Texture::createTextureView() {
_gpuTextureView->gpuTexture = _gpuTexture;
_gpuTextureView->type = _viewInfo.type;
_gpuTextureView->format = _viewInfo.format;
_gpuTextureView->baseLevel = _viewInfo.baseLevel;
_gpuTextureView->levelCount = _viewInfo.levelCount;
_gpuTextureView->baseLayer = _viewInfo.baseLayer;
_gpuTextureView->layerCount = _viewInfo.layerCount;
_gpuTextureView->basePlane = _viewInfo.basePlane;
_gpuTextureView->planeCount = _viewInfo.planeCount;
cmdFuncGLES3CreateTextureView(GLES3Device::getInstance(), _gpuTextureView);
}
void GLES3Texture::doDestroy() {
CC_SAFE_DELETE(_gpuTextureView);
if (_gpuTexture) {
if (!_isTextureView) {
if (_gpuTexture->memoryAllocated) {
GLES3Device::getInstance()->getMemoryStatus().textureSize -= _size;
CC_PROFILE_MEMORY_DEC(Texture, _size);
}
cmdFuncGLES3DestroyTexture(GLES3Device::getInstance(), _gpuTexture);
GLES3Device::getInstance()->framebufferHub()->disengage(_gpuTexture);
delete _gpuTexture;
}
_gpuTexture = nullptr;
}
}
void GLES3Texture::doResize(uint32_t width, uint32_t height, uint32_t size) {
if (!_isTextureView && _gpuTexture->memoryAllocated) {
GLES3Device::getInstance()->getMemoryStatus().textureSize -= _size;
CC_PROFILE_MEMORY_DEC(Texture, _size);
}
_gpuTexture->width = width;
_gpuTexture->height = height;
_gpuTexture->size = size;
_gpuTexture->mipLevel = _info.levelCount;
cmdFuncGLES3ResizeTexture(GLES3Device::getInstance(), _gpuTexture);
GLES3Device::getInstance()->framebufferHub()->update(_gpuTexture);
if (!_isTextureView && _gpuTexture->memoryAllocated) {
GLES3Device::getInstance()->getMemoryStatus().textureSize += size;
CC_PROFILE_MEMORY_INC(Texture, size);
}
}
uint32_t GLES3Texture::getGLTextureHandle() const noexcept {
const auto *gpuTexture = _gpuTexture;
if (!gpuTexture) {
return 0;
}
if (gpuTexture->glTexture) {
return gpuTexture->glTexture;
}
if (gpuTexture->glRenderbuffer) {
return gpuTexture->glRenderbuffer;
}
return 0;
}
///////////////////////////// Swapchain Specific /////////////////////////////
void GLES3Texture::doInit(const SwapchainTextureInfo & /*info*/) {
_gpuTexture = ccnew GLES3GPUTexture;
_gpuTexture->type = _info.type;
_gpuTexture->format = _info.format;
_gpuTexture->usage = _info.usage;
_gpuTexture->width = _info.width;
_gpuTexture->height = _info.height;
_gpuTexture->depth = _info.depth;
_gpuTexture->arrayLayer = _info.layerCount;
_gpuTexture->mipLevel = _info.levelCount;
_gpuTexture->glSamples = static_cast<GLint>(_info.samples);
_gpuTexture->flags = _info.flags;
_gpuTexture->size = _size;
_gpuTexture->memoryAllocated = false;
_gpuTexture->swapchain = static_cast<GLES3Swapchain *>(_swapchain)->gpuSwapchain();
_gpuTextureView = ccnew GLES3GPUTextureView;
createTextureView();
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,59 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "GLES3Std.h"
#include "gfx-base/GFXTexture.h"
namespace cc {
namespace gfx {
struct GLES3GPUTexture;
struct GLES3GPUTextureView;
class CC_GLES3_API GLES3Texture final : public Texture {
public:
GLES3Texture();
~GLES3Texture() override;
inline GLES3GPUTexture *gpuTexture() const { return _gpuTexture; }
inline GLES3GPUTextureView *gpuTextureView() const { return _gpuTextureView; }
uint32_t getGLTextureHandle() const noexcept override;
protected:
void doInit(const TextureInfo &info) override;
void doInit(const TextureViewInfo &info) override;
void doDestroy() override;
void doResize(uint32_t width, uint32_t height, uint32_t size) override;
void doInit(const SwapchainTextureInfo &info) override;
void createTextureView();
GLES3GPUTexture *_gpuTexture = nullptr;
GLES3GPUTextureView *_gpuTextureView = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,155 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Wrangler.h"
#include <string>
#include "base/Log.h"
#include "base/memory/Memory.h"
#if defined(_WIN32) && !defined(ANDROID)
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
static HMODULE libegl = NULL;
static HMODULE libgles = NULL;
static PFNGLES3WLOADPROC pfnGles3wLoad = NULL;
bool gles3wOpen() {
std::string eglPath = "libEGL.dll";
std::string glesPath = "libGLESv2.dll";
#if CC_EDITOR
// In editor,there are same library,so we need to use abs path to load them.
HMODULE engine = NULL;
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCWSTR)&gles3wOpen, &engine) != 0) {
std::string dir;
int times = 1;
do {
auto size = MAX_PATH * times++;
char *path = static_cast<char *>(CC_MALLOC(size));
if (path) {
GetModuleFileNameA(engine, path, size);
dir = path;
}
CC_FREE(path);
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
dir = dir.substr(0, dir.rfind("\\") + 1);
eglPath = dir + eglPath;
glesPath = dir + glesPath;
} else {
DWORD err = GetLastError();
CC_LOG_WARNING("Failed to get abs path for editor,error code:%lu", err);
}
#endif
libegl = LoadLibraryA(eglPath.c_str());
libgles = LoadLibraryA(glesPath.c_str());
return (libegl && libgles);
}
bool gles3wClose() {
bool ret = true;
if (libegl) {
ret &= FreeLibrary(libegl) ? true : false;
libegl = NULL;
}
if (libgles) {
ret &= FreeLibrary(libgles) ? true : false;
libgles = NULL;
}
return ret;
}
void *gles3wLoad(const char *proc) {
void *res = nullptr;
if (eglGetProcAddress) res = (void *)eglGetProcAddress(proc);
if (!res) res = (void *)GetProcAddress(libegl, proc);
return res;
}
#elif defined(__EMSCRIPTEN__)
bool gles3wOpen() { return true; }
bool gles3wClose() { return true; }
void *gles3wLoad(const char *proc) {
return (void *)eglGetProcAddress(proc);
}
#else
#include <dlfcn.h>
static void *libegl = nullptr;
static void *libgles = nullptr;
static PFNGLES3WLOADPROC pfnGles3wLoad = nullptr;
bool gles3wOpen() {
libegl = dlopen("libEGL.so", RTLD_LAZY | RTLD_GLOBAL);
libgles = dlopen("libGLESv3.so", RTLD_LAZY | RTLD_GLOBAL);
return (libegl && libgles);
}
bool gles3wClose() {
bool ret = true;
if (libegl) {
ret &= dlclose(libegl) == 0;
libegl = nullptr;
}
if (libgles) {
ret &= dlclose(libgles) == 0;
libgles = nullptr;
}
return ret;
}
void *gles3wLoad(const char *proc) {
void *res = nullptr;
if (eglGetProcAddress) res = reinterpret_cast<void *>(eglGetProcAddress(proc));
if (!res) res = dlsym(libegl, proc);
return res;
}
#endif
PFNGLES3WLOADPROC pfnGLES3wLoadProc() {
return pfnGles3wLoad;
}
bool gles3wInit() {
if (!gles3wOpen()) {
return false;
}
eglwLoadProcs(gles3wLoad);
gles2wLoadProcs(gles3wLoad);
gles3wLoadProcs(gles3wLoad);
pfnGles3wLoad = gles3wLoad;
return true;
}
bool gles3wExit() {
return gles3wClose();
}

View File

@@ -0,0 +1,33 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "../gfx-gles-common/eglw.h"
#include "../gfx-gles-common/gles2w.h"
#include "../gfx-gles-common/gles3w.h"
PFNGLES3WLOADPROC pfnGLES3wLoadProc();
bool gles3wInit();
bool gles3wExit();

View File

@@ -0,0 +1,47 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3GeneralBarrier.h"
#include "../GLES3Commands.h"
#include "gfx-gles3/GLES3Device.h"
namespace cc {
namespace gfx {
GLES3GeneralBarrier::GLES3GeneralBarrier(const GeneralBarrierInfo &info) : GeneralBarrier(info) {
_typedID = generateObjectID<decltype(this)>();
_gpuBarrier = ccnew GLES3GPUGeneralBarrier;
_gpuBarrier->prevAccesses = info.prevAccesses;
_gpuBarrier->nextAccesses = info.nextAccesses;
cmdFuncGLES3CreateGeneralBarrier(GLES3Device::getInstance(), _gpuBarrier);
}
GLES3GeneralBarrier::~GLES3GeneralBarrier() {
CC_SAFE_DELETE(_gpuBarrier);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,47 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "../GLES3Std.h"
#include "gfx-base/states/GFXGeneralBarrier.h"
namespace cc {
namespace gfx {
struct GLES3GPUGeneralBarrier;
class CC_GLES3_API GLES3GeneralBarrier : public GeneralBarrier {
public:
explicit GLES3GeneralBarrier(const GeneralBarrierInfo &info);
~GLES3GeneralBarrier() override;
inline const GLES3GPUGeneralBarrier *gpuBarrier() const { return _gpuBarrier; }
protected:
GLES3GPUGeneralBarrier *_gpuBarrier = nullptr;
};
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,52 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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 "GLES3Sampler.h"
#include "../GLES3Commands.h"
#include "../GLES3Device.h"
namespace cc {
namespace gfx {
GLES3Sampler::GLES3Sampler(const SamplerInfo &info) : Sampler(info) {
_typedID = generateObjectID<decltype(this)>();
_gpuSampler = ccnew GLES3GPUSampler;
_gpuSampler->minFilter = _info.minFilter;
_gpuSampler->magFilter = _info.magFilter;
_gpuSampler->mipFilter = _info.mipFilter;
_gpuSampler->addressU = _info.addressU;
_gpuSampler->addressV = _info.addressV;
_gpuSampler->addressW = _info.addressW;
// GL is not thread-safe, so any actual gl invocations need to be deferred to device thread
cmdFuncGLES3PrepareSamplerInfo(GLES3Device::getInstance(), _gpuSampler);
}
GLES3Sampler::~GLES3Sampler() {
CC_SAFE_DELETE(_gpuSampler);
}
} // namespace gfx
} // namespace cc

View File

@@ -0,0 +1,47 @@
/****************************************************************************
Copyright (c) 2019-2023 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
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.
****************************************************************************/
#pragma once
#include "../GLES3Std.h"
#include "gfx-base/states/GFXSampler.h"
namespace cc {
namespace gfx {
class GLES3GPUSampler;
class CC_GLES3_API GLES3Sampler final : public Sampler {
public:
explicit GLES3Sampler(const SamplerInfo &info);
~GLES3Sampler() override;
inline GLES3GPUSampler *gpuSampler() const { return _gpuSampler; }
protected:
GLES3GPUSampler *_gpuSampler = nullptr;
};
} // namespace gfx
} // namespace cc