no message
This commit is contained in:
136
cocos/renderer/gfx-wgpu/CMakeLists.txt
Normal file
136
cocos/renderer/gfx-wgpu/CMakeLists.txt
Normal file
@@ -0,0 +1,136 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(APP_NAME "webgpu" CACHE STRING "Project Name")
|
||||
project(${APP_NAME}_wasm)
|
||||
|
||||
message(${CMAKE_BUILD_TYPE})
|
||||
if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
set(ENGINE_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
|
||||
include(${ENGINE_ROOT_DIR}/cmake/predefine.cmake)
|
||||
|
||||
include (${ENGINE_ROOT_DIR}/external/CMakeLists.txt)
|
||||
|
||||
add_definitions(-DBOOST_NO_CXX98_FUNCTION_BASE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wno-nonportable-include-path -fno-exceptions")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3 -D_DEBUG=1 -Wno-unused -O0 -std=c++17")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG=1 -O3 -std=c++17")
|
||||
|
||||
message(${CMAKE_BUILD_TYPE})
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
./states
|
||||
WGPU_STATES_SRC
|
||||
)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
.
|
||||
WGPU_IMPL_SRC
|
||||
)
|
||||
|
||||
set(WGPU_SRC
|
||||
${WGPU_STATES_SRC}
|
||||
${WGPU_IMPL_SRC}
|
||||
)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/base/threading
|
||||
COCOS_BASE_THREAD
|
||||
)
|
||||
list(FILTER COCOS_BASE_THREAD EXCLUDE REGEX "[\\w+]*.mm")
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/base
|
||||
COCOS_BASE
|
||||
)
|
||||
list(FILTER COCOS_BASE EXCLUDE REGEX "ZipUtils.*")
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/renderer/gfx-base
|
||||
GFX_BASE
|
||||
)
|
||||
list(FILTER GFX_BASE EXCLUDE REGEX "[\\w+]*SPIRVUtils.cpp")
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/renderer/gfx-base/states
|
||||
GFX_BASE_STATES
|
||||
)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/renderer/gfx-agent
|
||||
GFX_AGENT
|
||||
)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/renderer/gfx-validator
|
||||
GFX_VALIDATOR
|
||||
)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
../../../cocos/renderer/gfx-empty
|
||||
GFX_EMPTY
|
||||
)
|
||||
|
||||
# AUX_SOURCE_DIRECTORY(
|
||||
# ../../../cocos/renderer/pipeline
|
||||
# PIPELINE
|
||||
# )
|
||||
|
||||
set(RENDERER
|
||||
../../../cocos/renderer/GFXDeviceManager.h
|
||||
${GFX_BASE}
|
||||
${GFX_AGENT}
|
||||
${GFX_VALIDATOR}
|
||||
${GFX_EMPTY}
|
||||
${GFX_BASE_STATES}
|
||||
#${PIPELINE}
|
||||
)
|
||||
|
||||
set(NATIVE_SRC
|
||||
${COCOS_BASE}
|
||||
${COCOS_BASE_THREAD}
|
||||
${RENDERER}
|
||||
${WGPU_SRC}
|
||||
)
|
||||
|
||||
AUX_SOURCE_DIRECTORY(
|
||||
./
|
||||
WASM_EXPORTS
|
||||
)
|
||||
|
||||
add_executable(${APP_NAME}_wasm ${WASM_EXPORTS} ${NATIVE_SRC})
|
||||
|
||||
target_include_directories(
|
||||
${APP_NAME}_wasm PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include"
|
||||
${CC_EXTERNAL_INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${ENGINE_ROOT_DIR}
|
||||
${ENGINE_ROOT_DIR}/cocos
|
||||
${ENGINE_ROOT_DIR}/cocos/base
|
||||
${ENGINE_ROOT_DIR}/cocos/renderer
|
||||
${ENGINE_ROOT_DIR}/cocos/platform
|
||||
${ENGINE_ROOT_DIR}/cocos/renderer/core
|
||||
${CC_EXTERNAL_PRIVATE_INCLUDES}
|
||||
)
|
||||
|
||||
# message(${WGPU_EMS_EXTERNAL_LIBS})
|
||||
target_link_libraries(
|
||||
${APP_NAME}_wasm PRIVATE PUBLIC
|
||||
# ${WGPU_EMS_EXTERNAL_LIBS}
|
||||
)
|
||||
|
||||
set(EMS_LINK_FLAGS
|
||||
"-flto --bind --no-entry -O3 -s USE_ES6_IMPORT_META=0 -s EXPORT_ES6=1 -s MODULARIZE=1 -s EXPORT_NAME='wasmDevice' -s ENVIRONMENT=web -s WASM=1 -s USE_WEBGPU=1 -s NO_EXIT_RUNTIME=1 -s LLD_REPORT_UNDEFINED -s ALLOW_MEMORY_GROWTH=1"
|
||||
)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
string(APPEND EMS_LINK_FLAGS " -g -s ASSERTIONS=2")
|
||||
endif()
|
||||
|
||||
set_target_properties(${APP_NAME}_wasm PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${ENGINE_ROOT_DIR}/external/emscripten/webgpu)
|
||||
|
||||
set_target_properties(${APP_NAME}_wasm PROPERTIES CXX_STANDARD 17 LINK_FLAGS ${EMS_LINK_FLAGS})
|
||||
256
cocos/renderer/gfx-wgpu/WGPUBuffer.cpp
Normal file
256
cocos/renderer/gfx-wgpu/WGPUBuffer.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUBuffer.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUUtils.h"
|
||||
#include <boost/align/align_up.hpp>
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
CCWGPUBuffer *dftUniformBuffer = nullptr;
|
||||
CCWGPUBuffer *dftStorageBuffer = nullptr;
|
||||
static uint32_t BUFFER_ALIGNMENT = 16;
|
||||
} // namespace
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
CCWGPUBuffer::CCWGPUBuffer() : Buffer() {
|
||||
}
|
||||
|
||||
CCWGPUBuffer::~CCWGPUBuffer() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::doInit(const BufferInfo &info) {
|
||||
_gpuBufferObject = ccnew CCWGPUBufferObject;
|
||||
|
||||
if (hasFlag(_usage, BufferUsageBit::INDIRECT)) {
|
||||
size_t drawInfoCount = _size / sizeof(DrawInfo);
|
||||
_gpuBufferObject->indexedIndirectObjs.resize(drawInfoCount);
|
||||
_gpuBufferObject->indirectObjs.resize(drawInfoCount);
|
||||
}
|
||||
|
||||
_size = boost::alignment::align_up(_size, BUFFER_ALIGNMENT);
|
||||
|
||||
WGPUBufferDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.usage = toWGPUBufferUsage(info.usage),
|
||||
.size = _size,
|
||||
.mappedAtCreation = false, // hasFlag(info.memUsage, MemoryUsageBit::DEVICE),
|
||||
};
|
||||
|
||||
_gpuBufferObject->mapped = descriptor.mappedAtCreation;
|
||||
|
||||
if (info.memUsage == MemoryUsage::DEVICE) {
|
||||
descriptor.usage |= WGPUBufferUsage_CopyDst;
|
||||
} else if (info.memUsage == MemoryUsage::HOST) {
|
||||
descriptor.usage |= WGPUBufferUsage_CopySrc;
|
||||
} else if (info.memUsage == (MemoryUsage::HOST | MemoryUsage::DEVICE)) {
|
||||
descriptor.usage |= WGPUBufferUsage_CopySrc | WGPUBufferUsage_CopyDst;
|
||||
}
|
||||
|
||||
_gpuBufferObject->wgpuBuffer = wgpuDeviceCreateBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().bufferSize += _size;
|
||||
_internalChanged = true;
|
||||
} // namespace gfx
|
||||
|
||||
void CCWGPUBuffer::doInit(const BufferViewInfo &info) {
|
||||
_gpuBufferObject = ccnew CCWGPUBufferObject;
|
||||
_gpuBufferObject->wgpuBuffer = static_cast<CCWGPUBuffer *>(info.buffer)->gpuBufferObject()->wgpuBuffer;
|
||||
_internalChanged = true;
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::doDestroy() {
|
||||
if (_gpuBufferObject) {
|
||||
if (_gpuBufferObject->wgpuBuffer && !_isBufferView) {
|
||||
CCWGPUDevice::getInstance()->moveToTrash(_gpuBufferObject->wgpuBuffer);
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().bufferSize -= _size;
|
||||
}
|
||||
delete _gpuBufferObject;
|
||||
_gpuBufferObject = nullptr;
|
||||
}
|
||||
_internalChanged = true;
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::doResize(uint32_t size, uint32_t count) {
|
||||
if (_isBufferView) {
|
||||
printf("Resize is not support on buffer view!");
|
||||
return;
|
||||
}
|
||||
if (_gpuBufferObject->wgpuBuffer) {
|
||||
CCWGPUDevice::getInstance()->moveToTrash(_gpuBufferObject->wgpuBuffer);
|
||||
}
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().bufferSize -= _size;
|
||||
|
||||
if (hasFlag(_usage, BufferUsageBit::INDIRECT)) {
|
||||
const size_t drawInfoCount = _size / sizeof(DrawInfo);
|
||||
_gpuBufferObject->indexedIndirectObjs.resize(drawInfoCount);
|
||||
_gpuBufferObject->indirectObjs.resize(drawInfoCount);
|
||||
}
|
||||
|
||||
_size = boost::alignment::align_up(size, BUFFER_ALIGNMENT);
|
||||
|
||||
WGPUBufferDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.usage = toWGPUBufferUsage(_usage),
|
||||
.size = _size,
|
||||
.mappedAtCreation = false, // hasFlag(_memUsage, MemoryUsageBit::DEVICE),
|
||||
};
|
||||
_gpuBufferObject->wgpuBuffer = wgpuDeviceCreateBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().bufferSize += _size;
|
||||
|
||||
_internalChanged = true;
|
||||
} // namespace gfx
|
||||
|
||||
void bufferUpdateCallback(WGPUBufferMapAsyncStatus status, void *userdata) {
|
||||
if (status == WGPUBufferMapAsyncStatus_Success) {
|
||||
wgpuBufferUnmap(static_cast<WGPUBuffer>(userdata));
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::update(const void *buffer, uint32_t size) {
|
||||
// uint32_t alignedSize = ceil(size / 4.0) * 4;
|
||||
// size_t buffSize = alignedSize;
|
||||
// // if (hasFlag(_memUsage, MemoryUsageBit::DEVICE)) {
|
||||
// // auto *mappedBuffer = wgpuBufferGetMappedRange(_gpuBufferObject->wgpuBuffer, 0, alignedSize);
|
||||
// // memcpy(mappedBuffer, buffer, alignedSize);
|
||||
// // size_t offset = _isBufferView ? _offset : 0;
|
||||
// // wgpuBufferMapAsync(_gpuBufferObject->wgpuBuffer, WGPUMapMode_Write, offset, alignedSize, bufferUpdateCallback, _gpuBufferObject->wgpuBuffer);
|
||||
// // } else {
|
||||
// WGPUBufferDescriptor descriptor = {
|
||||
// .nextInChain = nullptr,
|
||||
// .label = nullptr,
|
||||
// .usage = WGPUBufferUsage_MapWrite | WGPUBufferUsage_CopySrc,
|
||||
// .size = alignedSize,
|
||||
// .mappedAtCreation = true,
|
||||
// };
|
||||
// WGPUBuffer stagingBuffer = wgpuDeviceCreateBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
// auto * mappedBuffer = wgpuBufferGetMappedRange(stagingBuffer, 0, alignedSize);
|
||||
// memcpy(mappedBuffer, buffer, size);
|
||||
// size_t offset = _isBufferView ? _offset : 0;
|
||||
// //}
|
||||
// wgpuBufferUnmap(static_cast<WGPUBuffer>(stagingBuffer));
|
||||
// //wgpuCommandEncoderCopyBufferToBuffer(WGPUCommandEncoder commandEncoder, WGPUBuffer source, uint64_t sourceOffset, WGPUBuffer destination, uint64_t destinationOffset, uint64_t size);
|
||||
// auto cmdEncoder = wgpuDeviceCreateCommandEncoder(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, nullptr);
|
||||
// wgpuCommandEncoderCopyBufferToBuffer(cmdEncoder, stagingBuffer, 0, _gpuBufferObject->wgpuBuffer, offset, alignedSize);
|
||||
// WGPUCommandBuffer commandBuffer = wgpuCommandEncoderFinish(cmdEncoder, nullptr);
|
||||
// wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &commandBuffer);
|
||||
// wgpuBufferRelease(stagingBuffer);
|
||||
// wgpuCommandEncoderRelease(cmdEncoder);
|
||||
// wgpuCommandBufferRelease(commandBuffer);
|
||||
|
||||
if (hasFlag(_usage, BufferUsageBit::INDIRECT)) {
|
||||
size_t drawInfoCount = size / sizeof(DrawInfo);
|
||||
const auto *drawInfo = static_cast<const DrawInfo *>(buffer);
|
||||
size_t offset = _isBufferView ? _offset : 0;
|
||||
update(drawInfo, drawInfoCount);
|
||||
} else {
|
||||
size_t offset = _isBufferView ? _offset : 0;
|
||||
uint32_t alignedSize = boost::alignment::align_up(size, BUFFER_ALIGNMENT);
|
||||
size_t buffSize = alignedSize;
|
||||
wgpuQueueWriteBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, _gpuBufferObject->wgpuBuffer, offset, buffer, buffSize);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::update(const DrawInfoList &drawInfos) {
|
||||
size_t drawInfoCount = drawInfos.size();
|
||||
if (drawInfoCount > 0) {
|
||||
void const *data = nullptr;
|
||||
size_t offset = _isBufferView ? _offset : 0;
|
||||
size_t buffSize = 0;
|
||||
// if (hasFlag(_usage, BufferUsageBit::INDIRECT))
|
||||
if (drawInfos[0].indexCount) {
|
||||
auto &indexedIndirectObjs = _gpuBufferObject->indexedIndirectObjs;
|
||||
for (size_t i = 0; i < drawInfoCount; i++) {
|
||||
indexedIndirectObjs[i].indexCount = drawInfos[i].indexCount;
|
||||
indexedIndirectObjs[i].instanceCount = drawInfos[i].instanceCount ? drawInfos[i].instanceCount : 1;
|
||||
indexedIndirectObjs[i].firstIndex = drawInfos[i].firstIndex;
|
||||
indexedIndirectObjs[i].baseVertex = drawInfos[i].vertexOffset;
|
||||
indexedIndirectObjs[i].firstInstance = 0; // check definition of indexedIndirectObj;
|
||||
}
|
||||
data = indexedIndirectObjs.data();
|
||||
buffSize = indexedIndirectObjs.size() * sizeof(CCWGPUDrawIndexedIndirectObject);
|
||||
} else {
|
||||
auto &indirectObjs = _gpuBufferObject->indirectObjs;
|
||||
for (size_t i = 0; i < drawInfoCount; i++) {
|
||||
indirectObjs[i].vertexCount = drawInfos[i].vertexCount;
|
||||
indirectObjs[i].instanceCount = drawInfos[i].instanceCount ? drawInfos[i].instanceCount : 1;
|
||||
indirectObjs[i].firstIndex = drawInfos[i].firstIndex;
|
||||
indirectObjs[i].firstInstance = 0; // check definition of indirectObj;
|
||||
}
|
||||
data = indirectObjs.data();
|
||||
buffSize = indirectObjs.size() * sizeof(CCWGPUDrawIndirectObject);
|
||||
}
|
||||
wgpuQueueWriteBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, _gpuBufferObject->wgpuBuffer, offset, data, buffSize);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::check() {
|
||||
if (_gpuBufferObject->mapped) {
|
||||
wgpuBufferUnmap(_gpuBufferObject->wgpuBuffer);
|
||||
_gpuBufferObject->mapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::stamp() {
|
||||
_internalChanged = false;
|
||||
}
|
||||
|
||||
CCWGPUBuffer *CCWGPUBuffer::defaultUniformBuffer() {
|
||||
if (!dftUniformBuffer) {
|
||||
BufferInfo info = {
|
||||
.usage = BufferUsageBit::UNIFORM,
|
||||
.memUsage = MemoryUsageBit::DEVICE,
|
||||
.size = 256,
|
||||
.flags = BufferFlagBit::NONE,
|
||||
};
|
||||
dftUniformBuffer = ccnew CCWGPUBuffer;
|
||||
dftUniformBuffer->initialize(info);
|
||||
}
|
||||
return dftUniformBuffer;
|
||||
}
|
||||
|
||||
CCWGPUBuffer *CCWGPUBuffer::defaultStorageBuffer() {
|
||||
if (!dftStorageBuffer) {
|
||||
BufferInfo info = {
|
||||
.usage = BufferUsageBit::STORAGE,
|
||||
.memUsage = MemoryUsageBit::DEVICE,
|
||||
.size = 256,
|
||||
.flags = BufferFlagBit::NONE,
|
||||
};
|
||||
dftStorageBuffer = ccnew CCWGPUBuffer;
|
||||
dftStorageBuffer->initialize(info);
|
||||
}
|
||||
return dftStorageBuffer;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
72
cocos/renderer/gfx-wgpu/WGPUBuffer.h
Normal file
72
cocos/renderer/gfx-wgpu/WGPUBuffer.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "base/std/container/vector.h"
|
||||
#include "gfx-base/GFXBuffer.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUBufferObject;
|
||||
|
||||
class CCWGPUBuffer final : public Buffer {
|
||||
public:
|
||||
CCWGPUBuffer();
|
||||
~CCWGPUBuffer();
|
||||
|
||||
inline CCWGPUBufferObject *gpuBufferObject() const { return _gpuBufferObject; }
|
||||
inline uint32_t getOffset() const { return _offset; }
|
||||
void update(const DrawInfoList &drawInfos);
|
||||
// used before unmap?
|
||||
void check();
|
||||
// stamp current resource handler
|
||||
void stamp();
|
||||
// resource handler changed?
|
||||
inline bool internalChanged() const { return _internalChanged; }
|
||||
|
||||
static CCWGPUBuffer *defaultUniformBuffer();
|
||||
static CCWGPUBuffer *defaultStorageBuffer();
|
||||
|
||||
void update(const void *buffer, uint32_t size) override;
|
||||
|
||||
EXPORT_EMS(
|
||||
void update(const emscripten::val &v, uint32_t size);)
|
||||
|
||||
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;
|
||||
|
||||
CCWGPUBufferObject *_gpuBufferObject = nullptr;
|
||||
|
||||
bool _internalChanged = false;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
885
cocos/renderer/gfx-wgpu/WGPUCommandBuffer.cpp
Normal file
885
cocos/renderer/gfx-wgpu/WGPUCommandBuffer.cpp
Normal file
@@ -0,0 +1,885 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUCommandBuffer.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include "WGPUBuffer.h"
|
||||
#include "WGPUDescriptorSet.h"
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUFrameBuffer.h"
|
||||
#include "WGPUInputAssembler.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUPipelineLayout.h"
|
||||
#include "WGPUPipelineState.h"
|
||||
#include "WGPUQueue.h"
|
||||
#include "WGPUShader.h"
|
||||
#include "WGPUSwapchain.h"
|
||||
#include "WGPUTexture.h"
|
||||
#include "WGPUUtils.h"
|
||||
#include "base/std/container/vector.h"
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
uint32_t dynamicOffsetBuffer[256];
|
||||
uint32_t dynBufferStartIndex = 0;
|
||||
} // namespace
|
||||
|
||||
CCWGPUCommandBuffer::CCWGPUCommandBuffer() : CommandBuffer() {
|
||||
}
|
||||
|
||||
CCWGPUCommandBuffer::~CCWGPUCommandBuffer() {
|
||||
doDestroy();
|
||||
}
|
||||
void CCWGPUCommandBuffer::doInit(const CommandBufferInfo &info) {
|
||||
_gpuCommandBufferObj = ccnew CCWGPUCommandBufferObject{};
|
||||
_gpuCommandBufferObj->type = info.type;
|
||||
_gpuCommandBufferObj->queue = static_cast<CCWGPUQueue *>(info.queue);
|
||||
_gpuCommandBufferObj->stateCache.descriptorSets.resize(4); //(info.queue->getDevice()->getMaxDescriptorSetLayoutBindings());
|
||||
memset(dynamicOffsetBuffer, 0, sizeof(dynamicOffsetBuffer));
|
||||
dynBufferStartIndex = 0;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::doDestroy() {
|
||||
if (_gpuCommandBufferObj) {
|
||||
if (!_gpuCommandBufferObj->redundantVertexBufferMap.empty()) {
|
||||
for (auto &pair : _gpuCommandBufferObj->redundantVertexBufferMap) {
|
||||
pair.second->destroy();
|
||||
delete pair.second;
|
||||
}
|
||||
}
|
||||
delete _gpuCommandBufferObj;
|
||||
_gpuCommandBufferObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::begin(RenderPass * /*renderPass*/, uint32_t /*subpass*/, Framebuffer * /*frameBuffer*/) {
|
||||
reset();
|
||||
|
||||
_numTriangles = 0;
|
||||
_numDrawCalls = 0;
|
||||
_numInstances = 0;
|
||||
|
||||
_gpuCommandBufferObj->wgpuCommandEncoder = wgpuDeviceCreateCommandEncoder(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, nullptr);
|
||||
|
||||
_attachmentSet.clear();
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::end() {
|
||||
auto *pipelineState = _gpuCommandBufferObj->stateCache.pipelineState;
|
||||
if (pipelineState) {
|
||||
_gpuCommandBufferObj->wgpuCommandBuffer = wgpuCommandEncoderFinish(_gpuCommandBufferObj->wgpuCommandEncoder, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const Color *colors, float depth, uint32_t stencil, CommandBuffer *const * /*secondaryCBs*/, uint32_t /*secondaryCBCount*/) {
|
||||
_renderPass = renderPass;
|
||||
_frameBuffer = fbo;
|
||||
|
||||
CCWGPUFramebuffer *ccFrameBuffer = static_cast<CCWGPUFramebuffer *>(fbo);
|
||||
const ColorAttachmentList &colorConfigs = renderPass->getColorAttachments();
|
||||
const DepthStencilAttachment &depthStencilConfig = renderPass->getDepthStencilAttachment();
|
||||
const TextureList &textures = ccFrameBuffer->getColorTextures();
|
||||
Texture *dsTexture = ccFrameBuffer->getDepthStencilTexture();
|
||||
CCWGPUSwapchain *swapchain = ccFrameBuffer->swapchain();
|
||||
|
||||
bool renderingFullScreen = true;
|
||||
bool needPartialClear = false;
|
||||
for (size_t i = 0; i < textures.size(); ++i) {
|
||||
if (renderArea.x != 0 || renderArea.y != 0 || renderArea.width != textures[i]->getWidth() || renderArea.height != textures[i]->getHeight()) {
|
||||
renderingFullScreen = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WGPURenderPassDescriptor &renderPassDesc = _gpuCommandBufferObj->renderPassDescriptor;
|
||||
ccstd::vector<WGPURenderPassColorAttachment> colorAttachments;
|
||||
if (colorConfigs.empty()) {
|
||||
renderPassDesc.nextInChain = nullptr;
|
||||
renderPassDesc.label = "swapchain";
|
||||
auto *targetTex = swapchain->gpuSwapchainObject()->swapchainColor;
|
||||
auto loadOp = WGPULoadOp_Clear;
|
||||
loadOp = _attachmentSet.find(targetTex) == _attachmentSet.end() ? loadOp : WGPULoadOp_Load;
|
||||
needPartialClear = !renderingFullScreen;
|
||||
WGPURenderPassColorAttachment color = {
|
||||
.view = swapchain->gpuSwapchainObject()->swapchainColor->gpuTextureObject()->selfView,
|
||||
.resolveTarget = nullptr, // TODO_Zeqiang: wgpu offscr msaa
|
||||
.loadOp = loadOp,
|
||||
.storeOp = toWGPUStoreOp(colorConfigs[0].storeOp),
|
||||
.clearValue = WGPUColor{0.2, 0.2, 0.2, 1.0},
|
||||
};
|
||||
colorAttachments.emplace_back(color);
|
||||
} else {
|
||||
renderPassDesc.nextInChain = nullptr;
|
||||
renderPassDesc.label = "attachments";
|
||||
|
||||
for (size_t i = 0; i < colorConfigs.size(); i++) {
|
||||
WGPURenderPassColorAttachment *colorAttchments = ccnew WGPURenderPassColorAttachment[colorConfigs.size()];
|
||||
auto loadOp = toWGPULoadOp(colorConfigs[i].loadOp);
|
||||
if (!renderingFullScreen) {
|
||||
needPartialClear = loadOp == WGPULoadOp_Clear;
|
||||
loadOp = _attachmentSet.find(textures[i]) == _attachmentSet.end() ? loadOp : WGPULoadOp_Load;
|
||||
}
|
||||
WGPURenderPassColorAttachment color = {
|
||||
.view = static_cast<CCWGPUTexture *>(textures[i])->gpuTextureObject()->selfView,
|
||||
.resolveTarget = nullptr, // TODO_Zeqiang: wgpu offscr msaa
|
||||
.loadOp = loadOp,
|
||||
.storeOp = toWGPUStoreOp(colorConfigs[i].storeOp),
|
||||
.clearValue = toWGPUColor(colors[i]),
|
||||
};
|
||||
colorAttachments.emplace_back(color);
|
||||
_attachmentSet.insert(textures[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::vector<WGPURenderPassDepthStencilAttachment> depthStencils;
|
||||
if(renderPass->getDepthStencilAttachment().format == Format::UNKNOWN) {
|
||||
renderPassDesc.depthStencilAttachment = nullptr;
|
||||
} else if(dsTexture) {
|
||||
WGPURenderPassDepthStencilAttachment depthStencil = {
|
||||
.view = static_cast<CCWGPUTexture *>(dsTexture)->gpuTextureObject()->selfView,
|
||||
.depthLoadOp = toWGPULoadOp(depthStencilConfig.depthLoadOp),
|
||||
.depthStoreOp = toWGPUStoreOp(depthStencilConfig.depthStoreOp),
|
||||
.depthClearValue = depth,
|
||||
.depthReadOnly = false,
|
||||
.stencilLoadOp = toWGPULoadOp(depthStencilConfig.stencilLoadOp),
|
||||
.stencilStoreOp = toWGPUStoreOp(depthStencilConfig.stencilStoreOp),
|
||||
.stencilClearValue = stencil,
|
||||
.stencilReadOnly = false,
|
||||
};
|
||||
depthStencils.emplace_back(depthStencil);
|
||||
} else {
|
||||
WGPURenderPassDepthStencilAttachment depthStencil = {
|
||||
.view = swapchain->gpuSwapchainObject()->swapchainDepthStencil->gpuTextureObject()->selfView,
|
||||
.depthLoadOp = toWGPULoadOp(depthStencilConfig.depthLoadOp),
|
||||
.depthStoreOp = toWGPUStoreOp(depthStencilConfig.depthStoreOp),
|
||||
.depthClearValue = depth,
|
||||
.depthReadOnly = false,
|
||||
.stencilLoadOp = toWGPULoadOp(depthStencilConfig.stencilLoadOp),
|
||||
.stencilStoreOp = toWGPUStoreOp(depthStencilConfig.stencilStoreOp),
|
||||
.stencilClearValue = stencil,
|
||||
.stencilReadOnly = false,
|
||||
};
|
||||
depthStencils.emplace_back(depthStencil);
|
||||
}
|
||||
|
||||
setViewport({renderArea.x, renderArea.y, renderArea.width, renderArea.height, 0.0F, 1.0F});
|
||||
setScissor(renderArea);
|
||||
|
||||
if (!renderingFullScreen && needPartialClear) {
|
||||
if (textures.size()) {
|
||||
for (size_t i = 0; i < textures.size(); ++i) {
|
||||
clearRect(this, textures[i], renderArea, colors[i]);
|
||||
}
|
||||
} else {
|
||||
auto *swapchainTex = swapchain->gpuSwapchainObject()->swapchainColor;
|
||||
clearRect(this, swapchainTex, renderArea, colors[0]);
|
||||
}
|
||||
}
|
||||
|
||||
_gpuCommandBufferObj->renderPassBegan = true;
|
||||
|
||||
renderPassDesc.colorAttachments = colorAttachments.data();
|
||||
renderPassDesc.colorAttachmentCount = colorAttachments.size();
|
||||
renderPassDesc.depthStencilAttachment = depthStencils.empty() ? nullptr : depthStencils.data();
|
||||
_gpuCommandBufferObj->wgpuRenderPassEncoder = wgpuCommandEncoderBeginRenderPass(_gpuCommandBufferObj->wgpuCommandEncoder, &renderPassDesc);
|
||||
} // namespace gfx
|
||||
|
||||
void CCWGPUCommandBuffer::endRenderPass() {
|
||||
wgpuRenderPassEncoderEnd(_gpuCommandBufferObj->wgpuRenderPassEncoder);
|
||||
wgpuRenderPassEncoderRelease(_gpuCommandBufferObj->wgpuRenderPassEncoder);
|
||||
_gpuCommandBufferObj->wgpuRenderPassEncoder = wgpuDefaultHandle;
|
||||
|
||||
for (auto &descObj : _gpuCommandBufferObj->stateCache.descriptorSets) {
|
||||
descObj.descriptorSet = nullptr;
|
||||
descObj.dynamicOffsetCount = 0;
|
||||
descObj.dynamicOffsets = nullptr;
|
||||
dynBufferStartIndex = 0;
|
||||
}
|
||||
_gpuCommandBufferObj->renderPassBegan = false;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::insertMarker(const MarkerInfo &marker) {
|
||||
std::ignore = marker;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::beginMarker(const MarkerInfo &marker) {
|
||||
std::ignore = marker;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::endMarker() {
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::bindPipelineState(PipelineState *pso) {
|
||||
_gpuCommandBufferObj->stateCache.pipelineState = static_cast<CCWGPUPipelineState *>(pso);
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, uint32_t dynamicOffsetCount, const uint32_t *dynamicOffsets) {
|
||||
uint32_t dynOffsetCount = dynamicOffsetCount;
|
||||
const uint32_t *dynOffsets = dynamicOffsets;
|
||||
auto &descriptorSets = _gpuCommandBufferObj->stateCache.descriptorSets;
|
||||
|
||||
auto *ccDescriptorSet = static_cast<CCWGPUDescriptorSet *>(descriptorSet);
|
||||
if (ccDescriptorSet->dynamicOffsetCount() == 0) {
|
||||
dynOffsets = nullptr;
|
||||
} else {
|
||||
memcpy(dynamicOffsetBuffer + dynBufferStartIndex, dynamicOffsets, sizeof(uint32_t) * dynamicOffsetCount);
|
||||
dynOffsets = dynamicOffsetBuffer + dynBufferStartIndex;
|
||||
dynBufferStartIndex += dynamicOffsetCount;
|
||||
}
|
||||
|
||||
CCWGPUDescriptorSetObject dsObj = {
|
||||
.descriptorSet = ccDescriptorSet,
|
||||
.dynamicOffsetCount = dynOffsetCount, // dynamicOffsetCount,
|
||||
.dynamicOffsets = dynOffsets, // dynamicOffsets,
|
||||
};
|
||||
|
||||
descriptorSets[set] = dsObj;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::bindInputAssembler(InputAssembler *ia) {
|
||||
_gpuCommandBufferObj->stateCache.inputAssembler = static_cast<CCWGPUInputAssembler *>(ia);
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setViewport(const Viewport &vp) {
|
||||
_gpuCommandBufferObj->stateCache.viewport = {vp.left, vp.top, vp.width, vp.height, vp.minDepth, vp.maxDepth};
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setScissor(const Rect &rect) {
|
||||
_gpuCommandBufferObj->stateCache.rect = rect;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setLineWidth(float /*width*/) {
|
||||
printf("linewith not support in webGPU, ignored.");
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setDepthBias(float constant, float clamp, float slope) {
|
||||
_gpuCommandBufferObj->stateCache.depthBiasConstant = constant;
|
||||
_gpuCommandBufferObj->stateCache.depthBiasClamp = clamp;
|
||||
_gpuCommandBufferObj->stateCache.depthBiasSlope = slope;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setBlendConstants(const Color &constants) {
|
||||
_gpuCommandBufferObj->stateCache.blendConstants = constants;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setDepthBound(float minBounds, float maxBounds) {
|
||||
_gpuCommandBufferObj->stateCache.depthMinBound = minBounds;
|
||||
_gpuCommandBufferObj->stateCache.depthMaxBound = maxBounds;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setStencilWriteMask(StencilFace face, uint32_t mask) {
|
||||
_gpuCommandBufferObj->stateCache.stencilMasks[face].writeMask = mask;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::setStencilCompareMask(StencilFace face, uint32_t ref, uint32_t mask) {
|
||||
_gpuCommandBufferObj->stateCache.stencilMasks[face].compareRef = ref;
|
||||
_gpuCommandBufferObj->stateCache.stencilMasks[face].compareMask = mask;
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::bindStates() {
|
||||
auto *pipelineState = static_cast<CCWGPUPipelineState *>(_gpuCommandBufferObj->stateCache.pipelineState);
|
||||
if (!pipelineState) {
|
||||
return;
|
||||
}
|
||||
ccstd::set<uint8_t> setInUse;
|
||||
|
||||
auto *pipelineLayout = static_cast<CCWGPUPipelineLayout *>(pipelineState->layout());
|
||||
const auto &setLayouts = pipelineLayout->getSetLayouts();
|
||||
bool pipelineLayoutChanged = false;
|
||||
|
||||
if (pipelineState->getBindPoint() == PipelineBindPoint::GRAPHICS) {
|
||||
// bindgroup & descriptorset
|
||||
const auto &descriptorSets = _gpuCommandBufferObj->stateCache.descriptorSets;
|
||||
for (size_t i = 0; i < setLayouts.size(); i++) {
|
||||
if (descriptorSets[i].descriptorSet) {
|
||||
// optional: prune descriptor set for redundant resources
|
||||
{
|
||||
auto *ccShader = static_cast<CCWGPUShader *>(pipelineState->getShader());
|
||||
const auto &bindingInshader = ccShader->gpuShaderObject()->bindings;
|
||||
if (bindingInshader.size() > i) {
|
||||
descriptorSets[i].descriptorSet->prune(bindingInshader[i]);
|
||||
} else {
|
||||
descriptorSets[i].descriptorSet->prune({});
|
||||
}
|
||||
descriptorSets[i].descriptorSet->forceUpdate();
|
||||
}
|
||||
|
||||
descriptorSets[i].descriptorSet->prepare();
|
||||
|
||||
if (descriptorSets[i].descriptorSet->dynamicOffsetCount() != descriptorSets[i].dynamicOffsetCount) {
|
||||
std::string str = "force " + std::to_string(i);
|
||||
wgpuRenderPassEncoderSetLabel(_gpuCommandBufferObj->wgpuRenderPassEncoder, str.c_str());
|
||||
uint32_t *dynOffsets = dynamicOffsetBuffer;
|
||||
const auto &dynamicOffsets = descriptorSets[i].descriptorSet->dynamicOffsets();
|
||||
uint32_t givenOffsetIndex = 0;
|
||||
for (size_t j = 0; j < descriptorSets[i].descriptorSet->dynamicOffsetCount(); ++j) {
|
||||
if (j >= descriptorSets[i].dynamicOffsetCount) {
|
||||
dynOffsets[j] = 0;
|
||||
} else {
|
||||
dynOffsets[j] = descriptorSets[i].dynamicOffsets[givenOffsetIndex++];
|
||||
}
|
||||
}
|
||||
wgpuRenderPassEncoderSetBindGroup(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
i,
|
||||
descriptorSets[i].descriptorSet->gpuBindGroupObject()->bindgroup,
|
||||
descriptorSets[i].descriptorSet->dynamicOffsetCount(),
|
||||
dynOffsets);
|
||||
} else {
|
||||
std::string str = "same " + std::to_string(i);
|
||||
wgpuRenderPassEncoderSetLabel(_gpuCommandBufferObj->wgpuRenderPassEncoder, str.c_str());
|
||||
wgpuRenderPassEncoderSetBindGroup(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
i,
|
||||
descriptorSets[i].descriptorSet->gpuBindGroupObject()->bindgroup,
|
||||
descriptorSets[i].dynamicOffsetCount,
|
||||
descriptorSets[i].dynamicOffsets);
|
||||
}
|
||||
setInUse.insert(i);
|
||||
pipelineLayoutChanged |= (setLayouts[i] != descriptorSets[i].descriptorSet->getLayout());
|
||||
} else {
|
||||
// missing
|
||||
std::string str = "missing " + std::to_string(i);
|
||||
wgpuRenderPassEncoderSetLabel(_gpuCommandBufferObj->wgpuRenderPassEncoder, str.c_str());
|
||||
wgpuRenderPassEncoderSetBindGroup(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
i,
|
||||
static_cast<WGPUBindGroup>(CCWGPUDescriptorSet::defaultBindGroup()),
|
||||
0,
|
||||
nullptr);
|
||||
pipelineLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pipelineLayoutChanged && setLayouts.size()) {
|
||||
ccstd::vector<DescriptorSet *> dsSets;
|
||||
for (size_t i = 0; i < setLayouts.size(); i++) {
|
||||
dsSets.push_back(descriptorSets[i].descriptorSet);
|
||||
}
|
||||
createPipelineLayoutFallback(dsSets, pipelineLayout, false);
|
||||
} else {
|
||||
pipelineLayout->prepare(setInUse);
|
||||
}
|
||||
|
||||
pipelineState->check(_renderPass, 1);
|
||||
pipelineState->prepare(setInUse);
|
||||
|
||||
const auto &pplLayout = static_cast<const CCWGPUPipelineLayout *>(pipelineState->ppl());
|
||||
|
||||
// pipeline state
|
||||
wgpuRenderPassEncoderSetPipeline(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
pipelineState->gpuPipelineStateObject()->wgpuRenderPipeline);
|
||||
|
||||
// input assembler
|
||||
const auto *ia = _gpuCommandBufferObj->stateCache.inputAssembler;
|
||||
const auto &vertexBufferList = ia->getVertexBuffers();
|
||||
for (size_t i = 0; i < vertexBufferList.size(); i++) {
|
||||
const auto *vertexBuffer = static_cast<CCWGPUBuffer *>(vertexBufferList[i]);
|
||||
wgpuRenderPassEncoderSetVertexBuffer(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
i,
|
||||
vertexBuffer->gpuBufferObject()->wgpuBuffer,
|
||||
vertexBuffer->getOffset(),
|
||||
vertexBuffer->getSize());
|
||||
}
|
||||
#if 1
|
||||
{
|
||||
// redundantVertexBufferMap
|
||||
const uint32_t maxAttrLen = pipelineState->gpuPipelineStateObject()->maxAttrLength;
|
||||
if (maxAttrLen != 0) {
|
||||
CCWGPUBuffer *buffer = nullptr;
|
||||
if (_gpuCommandBufferObj->redundantVertexBufferMap.find(maxAttrLen) != _gpuCommandBufferObj->redundantVertexBufferMap.end()) {
|
||||
buffer = _gpuCommandBufferObj->redundantVertexBufferMap[maxAttrLen];
|
||||
} else {
|
||||
BufferInfo info = {
|
||||
.usage = BufferUsageBit::VERTEX,
|
||||
.memUsage = MemoryUsageBit::DEVICE,
|
||||
.size = maxAttrLen,
|
||||
.flags = BufferFlagBit::NONE,
|
||||
};
|
||||
buffer = ccnew CCWGPUBuffer;
|
||||
buffer->initialize(info);
|
||||
_gpuCommandBufferObj->redundantVertexBufferMap.insert({maxAttrLen, buffer});
|
||||
printf("new vert buffer\n");
|
||||
}
|
||||
wgpuRenderPassEncoderSetVertexBuffer(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
vertexBufferList.size(),
|
||||
buffer->gpuBufferObject()->wgpuBuffer,
|
||||
0,
|
||||
maxAttrLen);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
const auto *indexBuffer = static_cast<CCWGPUBuffer *>(ia->getIndexBuffer());
|
||||
if (indexBuffer) {
|
||||
CC_ASSERT(indexBuffer->getStride() >= 2);
|
||||
wgpuRenderPassEncoderSetIndexBuffer(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
indexBuffer->gpuBufferObject()->wgpuBuffer,
|
||||
indexBuffer->getStride() == 2 ? WGPUIndexFormat::WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32,
|
||||
indexBuffer->getOffset(),
|
||||
indexBuffer->getSize());
|
||||
}
|
||||
|
||||
WGPUColor blendColor = toWGPUColor(_gpuCommandBufferObj->stateCache.blendConstants);
|
||||
wgpuRenderPassEncoderSetBlendConstant(_gpuCommandBufferObj->wgpuRenderPassEncoder, &blendColor);
|
||||
|
||||
CCWGPUFramebuffer *ccFrameBuffer = static_cast<CCWGPUFramebuffer *>(_frameBuffer);
|
||||
const TextureList &textures = ccFrameBuffer->getColorTextures();
|
||||
// minimum rendertarget w/h
|
||||
uint32_t rtWidth = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t rtHeight = std::numeric_limits<uint32_t>::max();
|
||||
for (size_t i = 0; i < textures.size(); i++) {
|
||||
rtWidth = rtWidth > textures[i]->getWidth() ? textures[i]->getWidth() : rtWidth;
|
||||
rtHeight = rtHeight > textures[i]->getHeight() ? textures[i]->getHeight() : rtHeight;
|
||||
}
|
||||
|
||||
const Viewport &vp = _gpuCommandBufferObj->stateCache.viewport;
|
||||
uint32_t left = vp.left > 0 ? vp.left : 0;
|
||||
uint32_t top = vp.top > 0 ? vp.top : 0;
|
||||
|
||||
uint32_t width = vp.left > 0 ? vp.width : vp.width + vp.left;
|
||||
width = left + width > rtWidth ? rtWidth - left : width;
|
||||
|
||||
uint32_t height = vp.top > 0 ? vp.height : vp.height + vp.top;
|
||||
height = top + height > rtHeight ? rtHeight - top : height;
|
||||
wgpuRenderPassEncoderSetViewport(_gpuCommandBufferObj->wgpuRenderPassEncoder, left, top, width, height, vp.minDepth, vp.maxDepth);
|
||||
|
||||
const Rect &rect = _gpuCommandBufferObj->stateCache.rect;
|
||||
left = rect.x > 0 ? rect.x : 0;
|
||||
top = rect.y > 0 ? rect.y : 0;
|
||||
width = rect.x > 0 ? rect.width : rect.width + rect.x;
|
||||
width = left + width > rtWidth ? rtWidth - left : width;
|
||||
height = rect.y > 0 ? rect.height : rect.height + rect.y;
|
||||
height = top + height > rtHeight ? rtHeight - top : height;
|
||||
wgpuRenderPassEncoderSetScissorRect(_gpuCommandBufferObj->wgpuRenderPassEncoder, left, top, width, height);
|
||||
|
||||
wgpuRenderPassEncoderSetStencilReference(_gpuCommandBufferObj->wgpuRenderPassEncoder, pipelineState->getDepthStencilState().stencilRefFront);
|
||||
} else if (pipelineState->getBindPoint() == PipelineBindPoint::COMPUTE) {
|
||||
auto *pipelineState = _gpuCommandBufferObj->stateCache.pipelineState;
|
||||
const auto &setLayouts = pipelineLayout->getSetLayouts();
|
||||
// bindgroup & descriptorset
|
||||
const auto &descriptorSets = _gpuCommandBufferObj->stateCache.descriptorSets;
|
||||
bool pipelineLayoutChanged = false;
|
||||
for (size_t i = 0; i < descriptorSets.size(); i++) {
|
||||
if (descriptorSets[i].descriptorSet) {
|
||||
// optional: prune descriptor set for redundant resources
|
||||
{
|
||||
auto *ccShader = static_cast<CCWGPUShader *>(pipelineState->getShader());
|
||||
const auto &bindingInshader = ccShader->gpuShaderObject()->bindings;
|
||||
if (bindingInshader.size() > i) {
|
||||
descriptorSets[i].descriptorSet->prune(bindingInshader[i]);
|
||||
} else {
|
||||
descriptorSets[i].descriptorSet->prune({});
|
||||
}
|
||||
descriptorSets[i].descriptorSet->forceUpdate();
|
||||
}
|
||||
|
||||
descriptorSets[i].descriptorSet->prepare();
|
||||
wgpuComputePassEncoderSetBindGroup(_gpuCommandBufferObj->wgpuComputeEncoder,
|
||||
i,
|
||||
descriptorSets[i].descriptorSet->gpuBindGroupObject()->bindgroup,
|
||||
descriptorSets[i].dynamicOffsetCount,
|
||||
descriptorSets[i].dynamicOffsets);
|
||||
pipelineLayoutChanged |= (setLayouts[i] != descriptorSets[i].descriptorSet->getLayout());
|
||||
setInUse.insert(i);
|
||||
} else {
|
||||
pipelineLayoutChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pipelineLayoutChanged && setLayouts.size()) {
|
||||
ccstd::vector<DescriptorSet *> dsSets;
|
||||
for (size_t i = 0; i < setLayouts.size(); i++) {
|
||||
dsSets.push_back(descriptorSets[i].descriptorSet);
|
||||
}
|
||||
createPipelineLayoutFallback(dsSets, pipelineLayout, true);
|
||||
} else {
|
||||
pipelineLayout->prepare(setInUse);
|
||||
}
|
||||
|
||||
pipelineState->prepare(setInUse);
|
||||
wgpuComputePassEncoderSetPipeline(_gpuCommandBufferObj->wgpuComputeEncoder,
|
||||
pipelineState->gpuPipelineStateObject()->wgpuComputePipeline);
|
||||
|
||||
} else {
|
||||
printf("wrong pipeline state bind point.");
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::nextSubpass() {
|
||||
printf("@hana-alice to implement.");
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::draw(const DrawInfo &info) {
|
||||
bindStates();
|
||||
|
||||
auto *ia = static_cast<CCWGPUInputAssembler *>(_gpuCommandBufferObj->stateCache.inputAssembler);
|
||||
if (ia->getIndirectBuffer()) {
|
||||
auto *indirectBuffer = static_cast<CCWGPUBuffer *>(ia->getIndirectBuffer());
|
||||
bool multiDrawIndirectSupport = false;
|
||||
|
||||
// indirectSupport not support, emscripten webgpu ver < 2021
|
||||
// https://github.com/gpuweb/gpuweb/issues/1354
|
||||
if (multiDrawIndirectSupport) {
|
||||
// todo
|
||||
} else {
|
||||
if (info.indexCount) {
|
||||
// indexedIndirect not supported, emsdk 2.0.26
|
||||
uint32_t drawInfoCount = indirectBuffer->getCount();
|
||||
for (size_t i = 0; i < drawInfoCount; i++) {
|
||||
wgpuRenderPassEncoderDrawIndexedIndirect(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
indirectBuffer->gpuBufferObject()->wgpuBuffer,
|
||||
indirectBuffer->getOffset() + i * sizeof(CCWGPUDrawIndexedIndirectObject));
|
||||
}
|
||||
} else {
|
||||
uint32_t drawInfoCount = indirectBuffer->getCount();
|
||||
for (size_t i = 0; i < drawInfoCount; i++) {
|
||||
wgpuRenderPassEncoderDrawIndirect(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
indirectBuffer->gpuBufferObject()->wgpuBuffer,
|
||||
indirectBuffer->getOffset() + i * sizeof(CCWGPUDrawIndirectObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto *indexBuffer = static_cast<CCWGPUBuffer *>(ia->getIndexBuffer());
|
||||
bool drawIndexed = indexBuffer && info.indexCount;
|
||||
uint32_t instanceCount = std::max(info.instanceCount, 1U);
|
||||
|
||||
if (drawIndexed) {
|
||||
wgpuRenderPassEncoderDrawIndexed(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
info.indexCount,
|
||||
instanceCount,
|
||||
info.firstIndex,
|
||||
info.vertexOffset,
|
||||
info.firstInstance);
|
||||
} else {
|
||||
wgpuRenderPassEncoderDraw(_gpuCommandBufferObj->wgpuRenderPassEncoder,
|
||||
info.vertexCount,
|
||||
instanceCount,
|
||||
info.firstVertex,
|
||||
info.firstInstance);
|
||||
}
|
||||
|
||||
++_numDrawCalls;
|
||||
_numInstances += info.instanceCount;
|
||||
if (_gpuCommandBufferObj->stateCache.pipelineState) {
|
||||
uint32_t indexCount = drawIndexed ? info.indexCount : info.vertexCount;
|
||||
switch (_gpuCommandBufferObj->stateCache.pipelineState->getPrimitive()) {
|
||||
case PrimitiveMode::TRIANGLE_LIST:
|
||||
_numTriangles += indexCount / 3 * instanceCount;
|
||||
break;
|
||||
case PrimitiveMode::TRIANGLE_STRIP:
|
||||
case PrimitiveMode::TRIANGLE_FAN:
|
||||
_numTriangles += (indexCount - 2) * instanceCount;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void updatBuffer(CCWGPUCommandBuffer *cmdBuffer, CCWGPUBuffer *buffer, const void *data, uint32_t buffSize) {
|
||||
WGPUBufferDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.usage = WGPUBufferUsage_MapWrite | WGPUBufferUsage_CopySrc,
|
||||
.size = buffSize,
|
||||
.mappedAtCreation = true,
|
||||
};
|
||||
|
||||
WGPUBuffer stagingBuffer = wgpuDeviceCreateBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
auto *mappedBuffer = wgpuBufferGetMappedRange(stagingBuffer, 0, buffSize);
|
||||
memcpy(mappedBuffer, data, buffSize);
|
||||
wgpuBufferUnmap(static_cast<WGPUBuffer>(stagingBuffer));
|
||||
|
||||
auto *bufferObj = buffer->gpuBufferObject();
|
||||
auto *commandBufferObj = cmdBuffer->gpuCommandBufferObject();
|
||||
size_t offset = buffer->isBufferView() ? buffer->getOffset() : 0;
|
||||
|
||||
if (commandBufferObj->wgpuCommandEncoder) {
|
||||
wgpuCommandEncoderCopyBufferToBuffer(commandBufferObj->wgpuCommandEncoder, stagingBuffer, 0, bufferObj->wgpuBuffer, offset, buffSize);
|
||||
} else {
|
||||
WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, nullptr);
|
||||
wgpuCommandEncoderCopyBufferToBuffer(cmdEncoder, stagingBuffer, 0, bufferObj->wgpuBuffer, offset, buffSize);
|
||||
WGPUCommandBuffer commandBuffer = wgpuCommandEncoderFinish(cmdEncoder, nullptr);
|
||||
wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &commandBuffer);
|
||||
wgpuCommandEncoderRelease(cmdEncoder);
|
||||
wgpuCommandBufferRelease(commandBuffer);
|
||||
}
|
||||
CCWGPUDevice::getInstance()->moveToTrash(stagingBuffer);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void CCWGPUCommandBuffer::updateIndirectBuffer(Buffer *buff, const DrawInfoList &drawInfos) {
|
||||
auto *ccBuffer = static_cast<CCWGPUBuffer *>(buff);
|
||||
size_t drawInfoCount = drawInfos.size();
|
||||
|
||||
if (drawInfoCount > 0) {
|
||||
auto *ccBuffer = static_cast<CCWGPUBuffer *>(buff);
|
||||
void *data = nullptr;
|
||||
uint32_t buffSize = 0;
|
||||
if (drawInfos[0].indexCount) {
|
||||
auto &indexedIndirectObjs = ccBuffer->gpuBufferObject()->indexedIndirectObjs;
|
||||
for (size_t i = 0; i < drawInfoCount; i++) {
|
||||
indexedIndirectObjs[i].indexCount = drawInfos[i].indexCount;
|
||||
indexedIndirectObjs[i].instanceCount = drawInfos[i].instanceCount ? drawInfos[i].instanceCount : 1;
|
||||
indexedIndirectObjs[i].firstIndex = drawInfos[i].firstIndex;
|
||||
indexedIndirectObjs[i].baseVertex = drawInfos[i].vertexOffset;
|
||||
indexedIndirectObjs[i].firstInstance = 0; // check definition of indexedIndirectObj;
|
||||
}
|
||||
data = indexedIndirectObjs.data();
|
||||
buffSize = indexedIndirectObjs.size() * sizeof(CCWGPUDrawIndexedIndirectObject);
|
||||
} else {
|
||||
auto &indirectObjs = ccBuffer->gpuBufferObject()->indirectObjs;
|
||||
for (size_t i = 0; i < drawInfoCount; i++) {
|
||||
indirectObjs[i].vertexCount = drawInfos[i].vertexCount;
|
||||
indirectObjs[i].instanceCount = drawInfos[i].instanceCount ? drawInfos[i].instanceCount : 1;
|
||||
indirectObjs[i].firstIndex = drawInfos[i].firstIndex;
|
||||
indirectObjs[i].firstInstance = 0; // check definition of indirectObj;
|
||||
}
|
||||
data = indirectObjs.data();
|
||||
buffSize = indirectObjs.size() * sizeof(CCWGPUDrawIndirectObject);
|
||||
}
|
||||
updatBuffer(this, ccBuffer, data, buffSize);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::updateBuffer(Buffer *buff, const void *data, uint32_t size) {
|
||||
uint32_t alignedSize = ceil(size / 4.0) * 4;
|
||||
size_t buffSize = alignedSize;
|
||||
auto *ccBuffer = static_cast<CCWGPUBuffer *>(buff);
|
||||
updatBuffer(this, ccBuffer, data, buffSize);
|
||||
}
|
||||
// WGPU_EXPORT void wgpuCommandEncoderCopyBufferToTexture(WGPUCommandEncoder commandEncoder, WGPUImageCopyBuffer const * source, WGPUImageCopyTexture const * destination, WGPUExtent3D const * copySize);
|
||||
void CCWGPUCommandBuffer::copyBuffersToTexture(const uint8_t *const *buffers, Texture *texture, const BufferTextureCopy *regions, uint32_t count) {
|
||||
auto encoder = _gpuCommandBufferObj->wgpuCommandEncoder;
|
||||
if (!encoder) {
|
||||
WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, nullptr);
|
||||
}
|
||||
|
||||
Format dstFormat = texture->getFormat();
|
||||
auto wgpuDevice = CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice;
|
||||
auto *ccTexture = static_cast<CCWGPUTexture *>(texture);
|
||||
auto blockSize = formatAlignment(dstFormat);
|
||||
|
||||
if (ccTexture->isTextureView()) {
|
||||
ccTexture = static_cast<CCWGPUTexture *>(ccTexture->getViewInfo().texture);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto ®ion = regions[i];
|
||||
auto bufferPixelWidth = region.buffStride > 0 ? region.buffStride : region.texExtent.width;
|
||||
auto bufferPixelHeight = region.buffTexHeight > 0 ? region.buffTexHeight : region.texExtent.height;
|
||||
auto bytesPerRow = formatSize(dstFormat, region.texExtent.width, 1, 1);
|
||||
auto bufferBytesPerRow = formatSize(dstFormat, bufferPixelWidth, 1, 1);
|
||||
auto bufferBytesPerImageSlice = formatSize(dstFormat, bufferPixelWidth, bufferPixelHeight, 1);
|
||||
auto bufferBytesPerImageLayer = formatSize(dstFormat, bufferPixelWidth, bufferPixelHeight, region.texExtent.depth);
|
||||
auto targetWidth = region.texExtent.width == 0 ? 0 : utils::alignTo(region.texExtent.width, blockSize.first);
|
||||
auto targetHeight = region.texExtent.height == 0 ? 0 : utils::alignTo(region.texExtent.height, blockSize.second);
|
||||
|
||||
// it's buffer data layout
|
||||
WGPUTextureDataLayout texDataLayout = {
|
||||
.offset = 0, // we always create a non-offset staging buffer or give interface a non-offset buffer address
|
||||
.bytesPerRow = bufferBytesPerRow,
|
||||
.rowsPerImage = bufferPixelHeight,
|
||||
};
|
||||
|
||||
bool compactInWidth = bufferPixelWidth == region.texExtent.width;
|
||||
for (size_t l = region.texSubres.baseArrayLayer; l < region.texSubres.layerCount + region.texSubres.baseArrayLayer; ++l) {
|
||||
for (size_t d = region.texOffset.z; d < region.texExtent.depth + region.texOffset.z; ++d) {
|
||||
if (compactInWidth) {
|
||||
auto *srcData = buffers[i] + region.buffOffset + (l - region.texSubres.baseArrayLayer) * bufferBytesPerImageLayer + (d - region.texOffset.z) * bufferBytesPerImageSlice;
|
||||
WGPUImageCopyTexture imageCopyTexture = {
|
||||
.texture = ccTexture->gpuTextureObject()->wgpuTexture,
|
||||
.mipLevel = region.texSubres.mipLevel,
|
||||
.origin = WGPUOrigin3D{
|
||||
static_cast<uint32_t>(region.texOffset.x),
|
||||
static_cast<uint32_t>(region.texOffset.y),
|
||||
static_cast<uint32_t>(d)},
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = targetWidth,
|
||||
.height = targetHeight,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
|
||||
WGPUBufferDescriptor bufferDesc = {
|
||||
.usage = WGPUBufferUsage_CopySrc,
|
||||
.size = bufferBytesPerImageSlice,
|
||||
.mappedAtCreation = true,
|
||||
};
|
||||
|
||||
auto stagingBuffer = wgpuDeviceCreateBuffer(wgpuDevice, &bufferDesc);
|
||||
auto *mappedBuffer = wgpuBufferGetMappedRange(stagingBuffer, 0, bufferBytesPerImageSlice);
|
||||
memcpy(mappedBuffer, buffers[i], bufferBytesPerImageSlice);
|
||||
wgpuBufferUnmap(static_cast<WGPUBuffer>(stagingBuffer));
|
||||
|
||||
WGPUImageCopyBuffer imageCopyBuffer = {
|
||||
.layout = texDataLayout,
|
||||
.buffer = stagingBuffer,
|
||||
};
|
||||
wgpuCommandEncoderCopyBufferToTexture(encoder, &imageCopyBuffer, &imageCopyTexture, &extent);
|
||||
CCWGPUDevice::getInstance()->moveToTrash(stagingBuffer);
|
||||
} else {
|
||||
for (size_t h = region.texOffset.y; h < region.texExtent.height + region.texOffset.y; h += blockSize.second) {
|
||||
auto *srcData = buffers[i] + region.buffOffset + (l - region.texSubres.baseArrayLayer) * bufferBytesPerImageLayer + (d - region.texOffset.z) * bufferBytesPerImageSlice +
|
||||
(h - region.texOffset.y) / blockSize.second * bufferBytesPerRow;
|
||||
WGPUImageCopyTexture imageCopyTexture = {
|
||||
.texture = ccTexture->gpuTextureObject()->wgpuTexture,
|
||||
.mipLevel = region.texSubres.mipLevel,
|
||||
.origin = WGPUOrigin3D{
|
||||
static_cast<uint32_t>(region.texOffset.x),
|
||||
static_cast<uint32_t>(h),
|
||||
static_cast<uint32_t>(d)},
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = targetWidth,
|
||||
.height = blockSize.second,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
|
||||
WGPUBufferDescriptor bufferDesc = {
|
||||
.usage = WGPUBufferUsage_CopySrc,
|
||||
.size = bytesPerRow,
|
||||
.mappedAtCreation = true,
|
||||
};
|
||||
|
||||
auto stagingBuffer = wgpuDeviceCreateBuffer(wgpuDevice, &bufferDesc);
|
||||
auto *mappedBuffer = wgpuBufferGetMappedRange(stagingBuffer, 0, bytesPerRow);
|
||||
memcpy(mappedBuffer, buffers[i], bytesPerRow);
|
||||
wgpuBufferUnmap(static_cast<WGPUBuffer>(stagingBuffer));
|
||||
|
||||
WGPUImageCopyBuffer imageCopyBuffer = {
|
||||
.layout = texDataLayout,
|
||||
.buffer = stagingBuffer,
|
||||
};
|
||||
wgpuCommandEncoderCopyBufferToTexture(encoder, &imageCopyBuffer, &imageCopyTexture, &extent);
|
||||
CCWGPUDevice::getInstance()->moveToTrash(stagingBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_gpuCommandBufferObj->wgpuCommandEncoder) {
|
||||
WGPUCommandBuffer commandBuffer = wgpuCommandEncoderFinish(encoder, nullptr);
|
||||
wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &commandBuffer);
|
||||
wgpuCommandEncoderRelease(encoder);
|
||||
wgpuCommandBufferRelease(commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) {
|
||||
// blitTexture(srcTexture, dstTexture, regions, count, Filter::POINT);
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::blitTexture(Texture *srcTexture, Texture *dstTexture, const TextureBlit *regions, uint32_t count, Filter filter) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto *srcTex = static_cast<CCWGPUTexture *>(srcTexture);
|
||||
auto *dstTex = static_cast<CCWGPUTexture *>(dstTexture);
|
||||
|
||||
WGPUOrigin3D srcOrigin = {
|
||||
.x = static_cast<uint32_t>(regions[i].srcOffset.x),
|
||||
.y = static_cast<uint32_t>(regions[i].srcOffset.y),
|
||||
.z = static_cast<uint32_t>(regions[i].srcSubres.baseArrayLayer),
|
||||
};
|
||||
|
||||
WGPUImageCopyTexture imageCopyTextureSrc = {
|
||||
.texture = srcTex->gpuTextureObject()->wgpuTexture,
|
||||
.mipLevel = regions[i].srcSubres.mipLevel,
|
||||
.origin = srcOrigin,
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUOrigin3D dstOrigin = {
|
||||
.x = static_cast<uint32_t>(regions[i].dstOffset.x),
|
||||
.y = static_cast<uint32_t>(regions[i].dstOffset.y),
|
||||
.z = static_cast<uint32_t>(regions[i].dstSubres.baseArrayLayer),
|
||||
};
|
||||
|
||||
WGPUImageCopyTexture imageCopyTextureDst = {
|
||||
.texture = dstTex->gpuTextureObject()->wgpuTexture,
|
||||
.mipLevel = regions[i].dstSubres.mipLevel,
|
||||
.origin = dstOrigin,
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = regions[i].dstExtent.width,
|
||||
.height = regions[i].dstExtent.height,
|
||||
.depthOrArrayLayers = regions[i].dstExtent.depth,
|
||||
};
|
||||
|
||||
wgpuCommandEncoderCopyTextureToTexture(_gpuCommandBufferObj->wgpuCommandEncoder, &imageCopyTextureSrc, &imageCopyTextureDst, &extent);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::execute(CommandBuffer *const * /*cmdBuffs*/, uint32_t /*count*/) {
|
||||
printf(".....\n");
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::dispatch(const DispatchInfo &info) {
|
||||
WGPUComputePassDescriptor cmoputeDesc = {};
|
||||
// if (!_gpuCommandBufferObj->wgpuComputeEncoder) {
|
||||
_gpuCommandBufferObj->wgpuComputeEncoder = wgpuCommandEncoderBeginComputePass(_gpuCommandBufferObj->wgpuCommandEncoder, &cmoputeDesc);
|
||||
// }
|
||||
|
||||
bindStates();
|
||||
|
||||
if (info.indirectBuffer) {
|
||||
auto *indirectBuffer = static_cast<CCWGPUBuffer *>(info.indirectBuffer);
|
||||
wgpuComputePassEncoderDispatchWorkgroupsIndirect(_gpuCommandBufferObj->wgpuComputeEncoder,
|
||||
indirectBuffer->gpuBufferObject()->wgpuBuffer,
|
||||
info.indirectOffset);
|
||||
|
||||
} else {
|
||||
wgpuComputePassEncoderDispatchWorkgroups(_gpuCommandBufferObj->wgpuComputeEncoder,
|
||||
info.groupCountX,
|
||||
info.groupCountY,
|
||||
info.groupCountZ);
|
||||
}
|
||||
wgpuComputePassEncoderEnd(_gpuCommandBufferObj->wgpuComputeEncoder);
|
||||
wgpuComputePassEncoderRelease(_gpuCommandBufferObj->wgpuComputeEncoder);
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::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) {
|
||||
}
|
||||
|
||||
void CCWGPUCommandBuffer::reset() {
|
||||
_gpuCommandBufferObj->wgpuCommandBuffer = wgpuDefaultHandle;
|
||||
_gpuCommandBufferObj->wgpuCommandEncoder = wgpuDefaultHandle;
|
||||
_gpuCommandBufferObj->wgpuRenderPassEncoder = wgpuDefaultHandle;
|
||||
_gpuCommandBufferObj->wgpuComputeEncoder = wgpuDefaultHandle;
|
||||
_gpuCommandBufferObj->computeCmdBuffs.clear();
|
||||
|
||||
CCWGPUStateCache stateCache = {};
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
119
cocos/renderer/gfx-wgpu/WGPUCommandBuffer.h
Normal file
119
cocos/renderer/gfx-wgpu/WGPUCommandBuffer.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include <functional>
|
||||
#include "base/std/container/vector.h"
|
||||
#include "gfx-base/GFXCommandBuffer.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUCommandBufferObject;
|
||||
|
||||
typedef std::function<void(CCWGPUCommandBufferObject *)> EncodeFunc;
|
||||
|
||||
class CCWGPUCommandBuffer final : public CommandBuffer {
|
||||
public:
|
||||
CCWGPUCommandBuffer();
|
||||
~CCWGPUCommandBuffer();
|
||||
|
||||
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 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 copyTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override;
|
||||
|
||||
void updateIndirectBuffer(Buffer *buff, const DrawInfoList &info);
|
||||
void resolveTexture(Texture *srcTexture, Texture *dstTexture, const TextureCopy *regions, uint32_t count) override{};
|
||||
|
||||
// TODO_Zeqiang: wgpu query pool
|
||||
void beginQuery(QueryPool *queryPool, uint32_t id) override{};
|
||||
void endQuery(QueryPool *queryPool, uint32_t id) override{};
|
||||
void resetQueryPool(QueryPool *queryPool) override{};
|
||||
void completeQueryPool(QueryPool *queryPool) override{};
|
||||
|
||||
inline CCWGPUCommandBufferObject *gpuCommandBufferObject() const { return _gpuCommandBufferObj; }
|
||||
|
||||
void beginRenderPass(RenderPass *renderPass, Framebuffer *fbo, const Rect &renderArea, const ColorList &colors, float depth, uint32_t stencil) {
|
||||
this->CommandBuffer::beginRenderPass(renderPass, fbo, renderArea, colors.data(), depth, stencil);
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
void bindDescriptorSet(uint32_t set, DescriptorSet *descriptorSet, const std::vector<uint32_t> &dynamicOffsets) {
|
||||
bindDescriptorSet(set, descriptorSet, dynamicOffsets.size(), dynamicOffsets.data());
|
||||
}
|
||||
|
||||
// emscripten export
|
||||
EXPORT_EMS(
|
||||
void updateBuffer(Buffer *buff, const emscripten::val &v, uint32_t size);)
|
||||
|
||||
protected:
|
||||
void doInit(const CommandBufferInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
// delay binding.
|
||||
void bindStates();
|
||||
|
||||
CCWGPUCommandBufferObject *_gpuCommandBufferObj = nullptr;
|
||||
|
||||
RenderPass *_renderPass = nullptr;
|
||||
Framebuffer *_frameBuffer = nullptr;
|
||||
|
||||
// first meet?
|
||||
std::set<void *> _attachmentSet;
|
||||
|
||||
// command buffer inner impl
|
||||
// std::queue<EncodeFunc> _renderPassFuncQ;
|
||||
// std::queue<EncodeFunc> _computeFuncQ;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
243
cocos/renderer/gfx-wgpu/WGPUDef.h
Normal file
243
cocos/renderer/gfx-wgpu/WGPUDef.h
Normal file
@@ -0,0 +1,243 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://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 <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/variadic/to_seq.hpp>
|
||||
#include <vector>
|
||||
#include "../gfx-base/GFXDef-common.h"
|
||||
#include "../gfx-base/GFXDef.h"
|
||||
|
||||
#ifdef CC_WGPU_WASM
|
||||
#define EXPORT_EMS(expr) expr
|
||||
#else
|
||||
#define EXPORT_EMS(expr)
|
||||
#endif
|
||||
|
||||
#ifdef CC_WGPU_DAWN
|
||||
#define EXPORT_DAWN(expr) expr
|
||||
#else
|
||||
#define EXPORT_DAWN(expr)
|
||||
#endif
|
||||
|
||||
#ifdef CC_WGPU_RS
|
||||
#define EXPORT_RS(expr) expr
|
||||
#else
|
||||
#define EXPORT_RS(expr)
|
||||
#endif
|
||||
|
||||
// https://github.com/emscripten-core/emscripten/issues/11070#issuecomment-717675128
|
||||
namespace emscripten {
|
||||
|
||||
template <typename T, typename TWrapper = T>
|
||||
std::vector<T> vecFromEMS(const val &vals) {
|
||||
uint32_t len = vals["length"].as<unsigned>();
|
||||
std::vector<T> res(len);
|
||||
const std::vector<val> Ts = vecFromJSArray<val>(vals);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
const val &t = Ts[i];
|
||||
res[i] = static_cast<T>(t.as<TWrapper>(allow_raw_pointers()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T, typename TWrapper = T>
|
||||
val vecToEMS(const std::vector<T> &Ts) {
|
||||
auto arr = val::array();
|
||||
for (size_t i = 0; i < Ts.size(); ++i) {
|
||||
arr.set(i, TWrapper(Ts[i]));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// template <typename T, typename std::enable_if<std::is_pointer<T>::value, bool>::type = true>
|
||||
// std::vector<T> ptrVecFromEMS(const val& vals) {
|
||||
// uint32_t len = vals["length"].as<unsigned>();
|
||||
// std::vector<T> res(len);
|
||||
// const std::vector<val> Ts = vecFromJSArray<val>(vals);
|
||||
// for (size_t i = 0; i < len; ++i) {
|
||||
// const val& t = Ts[i];
|
||||
// t.as<Texture*>(emscripten::allow_raw_pointers());
|
||||
// res[i] = reinterpret_cast<T>(t.as<int>());
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_pointer<T>::value, bool>::type = true>
|
||||
val ptrVecToEMS(const std::vector<T> &Ts) {
|
||||
auto arr = val::array();
|
||||
for (size_t i = 0; i < Ts.size(); ++i) {
|
||||
arr.set(i, Ts[i]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// vector<T> -> [] & [] ->vector<T>
|
||||
template <typename T, typename Allocator>
|
||||
struct BindingType<std::vector<T, Allocator>> {
|
||||
using ValBinding = BindingType<val>;
|
||||
using WireType = ValBinding::WireType;
|
||||
|
||||
static WireType toWireType(const std::vector<T, Allocator> &vec) {
|
||||
return ValBinding::toWireType(vecToEMS(vec));
|
||||
}
|
||||
|
||||
static std::vector<T, Allocator> fromWireType(WireType value) {
|
||||
return vecFromJSArray<T>(ValBinding::fromWireType(value), allow_raw_pointers());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypeID<T,
|
||||
typename std::enable_if_t<std::is_same<
|
||||
typename Canonicalized<T>::type,
|
||||
std::vector<typename Canonicalized<T>::type::value_type,
|
||||
typename Canonicalized<T>::type::allocator_type>>::value>> {
|
||||
static constexpr TYPEID get() { return TypeID<val>::get(); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace emscripten
|
||||
|
||||
template <typename T>
|
||||
struct GenInstance {
|
||||
static T instance() {
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
template <class R, class T>
|
||||
R getMemberType(R T::*);
|
||||
|
||||
#define MEMBER_TYPE(prop) decltype(getMemberType(prop))
|
||||
|
||||
template <typename T, typename U, typename V, typename FallBack = void>
|
||||
struct Exporter {
|
||||
Exporter(T &t, const char *propName, U V::*field, bool ignorePtrAssert = false) {
|
||||
t.field(propName, field);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename V>
|
||||
struct Exporter<T, U, V, typename std::enable_if<std::is_enum<U>::value>::type> {
|
||||
Exporter(T &t, const char *propName, U V::*field, bool ignorePtrAssert = false) {
|
||||
std::function<void(V & v, std::underlying_type_t<U> u)> set = [field](V &v, std::underlying_type_t<U> u) {
|
||||
v.*field = U{u};
|
||||
};
|
||||
std::function<std::underlying_type_t<U>(const V &v)> get = [field](const V &v) {
|
||||
return static_cast<std::underlying_type_t<U>>(v.*field);
|
||||
};
|
||||
t.field(propName, get, set);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename V>
|
||||
struct Exporter<T, U, V, typename std::enable_if<std::is_pointer<U>::value>::type> {
|
||||
Exporter(T &t, const char *propName, U V::*field) {
|
||||
static_assert(!std::is_pointer<U>::value, "Export pointer with struct, try EXPORT_STRUCT_NPOD!");
|
||||
}
|
||||
|
||||
Exporter(T &t, const char *propName, U V::*field, bool ignorePtrAssert) {
|
||||
t.field(propName, field);
|
||||
}
|
||||
};
|
||||
|
||||
#define PROCESS_STRUCT_MEMBERS(r, struct_name, property) \
|
||||
{ Exporter exporter(obj, BOOST_PP_STRINGIZE(property), &struct_name::property); }
|
||||
|
||||
#define EXPORT_STRUCT_POD(struct_name, ...) \
|
||||
{ \
|
||||
auto obj = value_object<struct_name>(#struct_name); \
|
||||
BOOST_PP_SEQ_FOR_EACH(PROCESS_STRUCT_MEMBERS, struct_name, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
#define PROCESS_STRUCT_MEMBERS_MAY_BE_PTR(r, struct_name, property) \
|
||||
{ Exporter exporter(obj, BOOST_PP_STRINGIZE(property), &struct_name::property, true); }
|
||||
|
||||
#define EXPORT_STRUCT_NPOD(struct_name, ...) \
|
||||
{ \
|
||||
auto obj = value_object<struct_name>(#struct_name); \
|
||||
BOOST_PP_SEQ_FOR_EACH(PROCESS_STRUCT_MEMBERS_MAY_BE_PTR, struct_name, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
#define SPECIALIZE_PTR_FOR_STRUCT(r, _, TYPE) \
|
||||
template <> \
|
||||
struct emscripten::internal::TypeID<std::remove_cv<cc::gfx::TYPE>::type *, void> { \
|
||||
static constexpr emscripten::internal::TYPEID get() { return emscripten::internal::TypeID<emscripten::internal::AllowedRawPointer<cc::gfx::TYPE>>::get(); } \
|
||||
}; \
|
||||
template <> \
|
||||
struct emscripten::internal::TypeID<const std::remove_cv<cc::gfx::TYPE>::type *, void> { \
|
||||
static constexpr emscripten::internal::TYPEID get() { return emscripten::internal::TypeID<emscripten::internal::AllowedRawPointer<cc::gfx::TYPE>>::get(); } \
|
||||
};
|
||||
|
||||
#define REGISTER_GFX_PTRS_FOR_STRUCT(...) \
|
||||
BOOST_PP_SEQ_FOR_EACH(SPECIALIZE_PTR_FOR_STRUCT, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__));
|
||||
|
||||
// specialize for void*
|
||||
template <>
|
||||
struct emscripten::internal::TypeID<void *, void> {
|
||||
static constexpr emscripten::internal::TYPEID get() { return emscripten::internal::TypeID<uintptr_t>::get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct emscripten::internal::TypeID<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
static constexpr emscripten::internal::TYPEID get() { return emscripten::internal::TypeID<typename std::underlying_type<T>::type>::get(); }
|
||||
};
|
||||
|
||||
namespace cc::gfx {
|
||||
|
||||
using ::emscripten::allow_raw_pointers;
|
||||
using ::emscripten::convertJSArrayToNumberVector;
|
||||
using ::emscripten::val;
|
||||
|
||||
// template <typename T, typename std::enable_if<std::is_pointer<T>::value, bool>::type = true>
|
||||
// std::vector<T> ptrVecFromEMS(const val& vals) {
|
||||
// uint32_t len = vals["length"].as<unsigned>();
|
||||
// std::vector<T> res(len);
|
||||
// const std::vector<val> Ts = vecFromJSArray<val>(vals);
|
||||
// for (size_t i = 0; i < len; ++i) {
|
||||
// const val& t = Ts[i];
|
||||
// t.as<Texture*>(emscripten::allow_raw_pointers());
|
||||
// res[i] = reinterpret_cast<T>(t.as<int>());
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
template <typename T, typename EnumFallBack = void>
|
||||
struct GetType {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetType<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
using type = typename std::underlying_type<T>::type;
|
||||
};
|
||||
|
||||
} // namespace cc::gfx
|
||||
325
cocos/renderer/gfx-wgpu/WGPUDescriptorSet.cpp
Normal file
325
cocos/renderer/gfx-wgpu/WGPUDescriptorSet.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUDescriptorSet.h"
|
||||
#include <emscripten/html5_webgpu.h>
|
||||
#include <algorithm>
|
||||
#include "WGPUBuffer.h"
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUSampler.h"
|
||||
#include "WGPUTexture.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
WGPUBindGroup dftBindGroup = wgpuDefaultHandle;
|
||||
|
||||
struct BindGroupCache {
|
||||
CCWGPUDescriptorSet *descriptorSet{nullptr};
|
||||
WGPUBindGroup bindGroup{wgpuDefaultHandle};
|
||||
ccstd::hash_t bornHash{0};
|
||||
};
|
||||
|
||||
thread_local ccstd::unordered_map<ccstd::hash_t, BindGroupCache> bindGroupMap;
|
||||
} // namespace
|
||||
|
||||
CCWGPUDescriptorSet::CCWGPUDescriptorSet() : DescriptorSet() {
|
||||
}
|
||||
|
||||
CCWGPUDescriptorSet::~CCWGPUDescriptorSet() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::clearCache() {
|
||||
if (!bindGroupMap.empty()) {
|
||||
for (auto &it : bindGroupMap) {
|
||||
wgpuBindGroupRelease(static_cast<WGPUBindGroup>(it.second.bindGroup));
|
||||
it.second.descriptorSet->_isDirty = true;
|
||||
}
|
||||
bindGroupMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::doInit(const DescriptorSetInfo &info) {
|
||||
_gpuBindGroupObj = ccnew CCWGPUBindGroupObject{};
|
||||
_gpuDescriptorObj = ccnew CCWGPUGPUDescriptorSetObject{};
|
||||
|
||||
auto *tLayout = const_cast<DescriptorSetLayout *>(_layout);
|
||||
auto *dsLayout = static_cast<CCWGPUDescriptorSetLayout *>(tLayout);
|
||||
const auto &bindings = dsLayout->getBindings();
|
||||
CCWGPUDeviceObject *deviceObj = CCWGPUDevice::getInstance()->gpuDeviceObject();
|
||||
for (size_t i = 0; i < bindings.size(); i++) {
|
||||
// effect.ts: INPUT_ATTACHMENT as combined texture but no sampler_texture desc type.
|
||||
if (hasFlag(COMBINED_ST_IN_USE, bindings[i].descriptorType)) {
|
||||
} else if (hasFlag(DESCRIPTOR_BUFFER_TYPE, bindings[i].descriptorType)) {
|
||||
if (hasAnyFlags(bindings[i].descriptorType, DescriptorType::DYNAMIC_STORAGE_BUFFER | DescriptorType::DYNAMIC_UNIFORM_BUFFER)) {
|
||||
_dynamicOffsets.emplace(i, bindings[i].binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_gpuDescriptorObj->gpuDescriptors.resize(bindings.size());
|
||||
_gpuDescriptorObj->descriptorIndices = info.layout->getBindingIndices();
|
||||
|
||||
_bindingSatisfied = [](uint32_t) { return true; };
|
||||
|
||||
(void)defaultBindGroup();
|
||||
}
|
||||
|
||||
ccstd::hash_t CCWGPUDescriptorSet::hash() const {
|
||||
ccstd::hash_t hash = _gpuBindGroupObj->bindGroupEntries.size();
|
||||
|
||||
for (const auto &entry : _gpuBindGroupObj->bindGroupEntries) {
|
||||
ccstd::hash_combine(hash, entry.binding);
|
||||
if (entry.buffer) {
|
||||
ccstd::hash_combine(hash, entry.buffer);
|
||||
ccstd::hash_combine(hash, entry.offset);
|
||||
ccstd::hash_combine(hash, entry.size);
|
||||
}
|
||||
if (entry.sampler) {
|
||||
ccstd::hash_combine(hash, entry.sampler);
|
||||
}
|
||||
if (entry.textureView) {
|
||||
ccstd::hash_combine(hash, entry.textureView);
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::doDestroy() {
|
||||
if (_gpuBindGroupObj) {
|
||||
delete _gpuBindGroupObj;
|
||||
_gpuBindGroupObj = nullptr;
|
||||
}
|
||||
if (_gpuDescriptorObj) {
|
||||
delete _gpuDescriptorObj;
|
||||
_gpuDescriptorObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::setGpuDescriptors(DescriptorSet *set) {
|
||||
auto *ccDesc = static_cast<CCWGPUDescriptorSet *>(set);
|
||||
const auto &descs = ccDesc->gpuDescriptors();
|
||||
|
||||
auto *tLayout = const_cast<DescriptorSetLayout *>(_layout);
|
||||
auto *dsLayout = static_cast<CCWGPUDescriptorSetLayout *>(tLayout);
|
||||
auto *srcTmpLayout = set->getLayout();
|
||||
|
||||
dsLayout->setBindings(srcTmpLayout->getBindings());
|
||||
dsLayout->setBindingIndices(srcTmpLayout->getBindingIndices());
|
||||
dsLayout->setDescriptorIndices(srcTmpLayout->getDescriptorIndices());
|
||||
|
||||
_gpuDescriptorObj->gpuDescriptors = descs.gpuDescriptors;
|
||||
_gpuDescriptorObj->descriptorIndices = descs.descriptorIndices;
|
||||
|
||||
_buffers = ccDesc->_buffers;
|
||||
_textures = ccDesc->_textures;
|
||||
_samplers = ccDesc->_samplers;
|
||||
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::prune(ccstd::vector<uint8_t> bindings) {
|
||||
_gpuBindGroupObj->bindingInShader = std::set<uint8_t>(bindings.begin(), bindings.end());
|
||||
|
||||
_bindingSatisfied = [&](uint32_t binding) {
|
||||
return (!_gpuBindGroupObj->bindingInShader.empty()) && (_gpuBindGroupObj->bindingInShader.find(binding) != _gpuBindGroupObj->bindingInShader.end());
|
||||
};
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::update() {
|
||||
if (!_isDirty) {
|
||||
return;
|
||||
}
|
||||
auto *tLayout = const_cast<DescriptorSetLayout *>(_layout);
|
||||
auto *dsLayout = static_cast<CCWGPUDescriptorSetLayout *>(tLayout);
|
||||
const auto &bindings = dsLayout->getBindings();
|
||||
|
||||
_gpuBindGroupObj->bindGroupEntries.clear();
|
||||
_dynamicOffsetNum = 0;
|
||||
|
||||
for (size_t i = 0; i < _gpuDescriptorObj->gpuDescriptors.size(); i++) {
|
||||
if (!_bindingSatisfied(bindings[i].binding)) {
|
||||
continue;
|
||||
}
|
||||
_gpuDescriptorObj->gpuDescriptors[i].type = bindings[i].descriptorType;
|
||||
const auto &binding = bindings[i];
|
||||
uint8_t resourceIndex = _layout->getDescriptorIndices()[i];
|
||||
if (hasFlag(DESCRIPTOR_BUFFER_TYPE, bindings[i].descriptorType)) {
|
||||
auto *ccBuffer = _buffers[resourceIndex].ptr ? static_cast<CCWGPUBuffer *>(_buffers[resourceIndex].ptr) : CCWGPUBuffer::defaultUniformBuffer();
|
||||
auto *buffer = static_cast<CCWGPUBuffer *>(ccBuffer);
|
||||
auto &bindGroupEntry = _gpuBindGroupObj->bindGroupEntries.emplace_back();
|
||||
buffer->check();
|
||||
bindGroupEntry.binding = binding.binding;
|
||||
bindGroupEntry.buffer = buffer->gpuBufferObject()->wgpuBuffer;
|
||||
bindGroupEntry.offset = buffer->getOffset();
|
||||
bindGroupEntry.size = buffer->getSize();
|
||||
dsLayout->updateBufferLayout(i, buffer, _buffers[resourceIndex].flags);
|
||||
uint8_t bindIndex = binding.binding;
|
||||
if (hasAnyFlags(binding.descriptorType, DescriptorType::DYNAMIC_STORAGE_BUFFER | DescriptorType::DYNAMIC_UNIFORM_BUFFER)) {
|
||||
_dynamicOffsets[i] = bindIndex;
|
||||
_dynamicOffsetNum++;
|
||||
}
|
||||
|
||||
_gpuDescriptorObj->gpuDescriptors[i].buffer = ccBuffer;
|
||||
} else if (hasFlag(COMBINED_ST_IN_USE, bindings[i].descriptorType)) {
|
||||
// printf("texture update %d %d %p\n", i, resourceIndex, _textures[resourceIndex].ptr);
|
||||
auto *ccTexture = _textures[resourceIndex].ptr ? static_cast<CCWGPUTexture *>(_textures[resourceIndex].ptr) : CCWGPUTexture::defaultCommonTexture();
|
||||
auto &bindGroupEntry = _gpuBindGroupObj->bindGroupEntries.emplace_back();
|
||||
bindGroupEntry.binding = binding.binding;
|
||||
bindGroupEntry.textureView = static_cast<WGPUTextureView>(ccTexture->getPlaneView(0));
|
||||
dsLayout->updateSampledTextureLayout(i, ccTexture);
|
||||
_gpuDescriptorObj->gpuDescriptors[i].texture = ccTexture;
|
||||
|
||||
auto &sBindGroupEntry = _gpuBindGroupObj->bindGroupEntries.emplace_back();
|
||||
auto *ccSampler = _samplers[resourceIndex].ptr ? static_cast<CCWGPUSampler *>(_samplers[resourceIndex].ptr) : CCWGPUSampler::defaultFilterableSampler();
|
||||
sBindGroupEntry.binding = binding.binding + CC_WGPU_MAX_ATTACHMENTS;
|
||||
sBindGroupEntry.sampler = ccSampler->gpuSampler();
|
||||
dsLayout->updateSamplerLayout(i, ccSampler);
|
||||
_gpuDescriptorObj->gpuDescriptors[i].sampler = ccSampler;
|
||||
} else if (DescriptorType::STORAGE_IMAGE == bindings[i].descriptorType || DescriptorType::TEXTURE == bindings[i].descriptorType) {
|
||||
auto *ccTexture = _textures[resourceIndex].ptr ? static_cast<CCWGPUTexture *>(_textures[resourceIndex].ptr) : CCWGPUTexture::defaultCommonTexture();
|
||||
auto &bindGroupEntry = _gpuBindGroupObj->bindGroupEntries.emplace_back();
|
||||
bindGroupEntry.binding = binding.binding;
|
||||
bindGroupEntry.textureView = static_cast<WGPUTextureView>(ccTexture->getPlaneView(0));
|
||||
if (DescriptorType::STORAGE_IMAGE == bindings[i].descriptorType) {
|
||||
dsLayout->updateStorageTextureLayout(i, ccTexture);
|
||||
} else {
|
||||
dsLayout->updateSampledTextureLayout(i, ccTexture);
|
||||
}
|
||||
_gpuDescriptorObj->gpuDescriptors[i].texture = ccTexture;
|
||||
} else if (DescriptorType::SAMPLER == bindings[i].descriptorType) {
|
||||
auto *ccSampler = _samplers[resourceIndex].ptr ? static_cast<CCWGPUSampler *>(_samplers[resourceIndex].ptr) : CCWGPUSampler::defaultFilterableSampler();
|
||||
auto &bindGroupEntry = _gpuBindGroupObj->bindGroupEntries.emplace_back();
|
||||
bindGroupEntry.binding = binding.binding;
|
||||
bindGroupEntry.sampler = ccSampler->gpuSampler();
|
||||
dsLayout->updateSamplerLayout(i, ccSampler);
|
||||
_gpuDescriptorObj->gpuDescriptors[i].sampler = ccSampler;
|
||||
} else {
|
||||
printf("*******unexpected binding type detected!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSet::prepare() {
|
||||
auto buffIter = std::find_if(_buffers.begin(), _buffers.end(), [](const ObjectWithId<Buffer> &buffer) {
|
||||
return buffer.ptr && static_cast<const CCWGPUBuffer *>(buffer.ptr)->internalChanged();
|
||||
});
|
||||
auto texIter = std::find_if(_textures.begin(), _textures.end(), [](const ObjectWithId<Texture> &texture) {
|
||||
return texture.ptr && static_cast<const CCWGPUTexture *>(texture.ptr)->internalChanged();
|
||||
});
|
||||
|
||||
bool forceUpdate = buffIter != _buffers.end() || texIter != _textures.end();
|
||||
|
||||
_isDirty |= forceUpdate;
|
||||
if (_isDirty) {
|
||||
update();
|
||||
}
|
||||
|
||||
if (_isDirty || forceUpdate || !_gpuBindGroupObj->bindgroup) {
|
||||
// TODDO(Zeqiang): no const cast
|
||||
auto *tLayout = const_cast<DescriptorSetLayout *>(_layout);
|
||||
auto *dsLayout = static_cast<CCWGPUDescriptorSetLayout *>(tLayout);
|
||||
|
||||
dsLayout->prepare(_gpuBindGroupObj->bindingInShader, forceUpdate);
|
||||
|
||||
const auto &entries = _gpuBindGroupObj->bindGroupEntries;
|
||||
if (_gpuBindGroupObj->bindingInShader.empty()) {
|
||||
_gpuBindGroupObj->bindgroup = dftBindGroup;
|
||||
_bornHash = 0;
|
||||
} else {
|
||||
_hash = hash();
|
||||
auto iter = bindGroupMap.find(_hash);
|
||||
if (iter == bindGroupMap.end()) {
|
||||
// layout might be changed later.
|
||||
_bornHash = dsLayout->getHash();
|
||||
CCWGPUDeviceObject *deviceObj = CCWGPUDevice::getInstance()->gpuDeviceObject();
|
||||
|
||||
label = std::to_string(_bornHash);
|
||||
WGPUBindGroupDescriptor bindGroupDesc = {
|
||||
.nextInChain = nullptr,
|
||||
.label = label.c_str(),
|
||||
.layout = dsLayout->gpuLayoutEntryObject()->bindGroupLayout,
|
||||
.entryCount = entries.size(),
|
||||
.entries = entries.data(),
|
||||
};
|
||||
|
||||
_gpuBindGroupObj->bindgroup = wgpuDeviceCreateBindGroup(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &bindGroupDesc);
|
||||
|
||||
_isDirty = false;
|
||||
if (buffIter != _buffers.end())
|
||||
std::for_each(_buffers.begin(), _buffers.end(), [](ObjectWithId<Buffer> &buffer) {
|
||||
if (buffer.ptr)
|
||||
static_cast<CCWGPUBuffer *>(buffer.ptr)->stamp();
|
||||
});
|
||||
if (texIter != _textures.end())
|
||||
std::for_each(_textures.begin(), _textures.end(), [](ObjectWithId<Texture> &texture) {
|
||||
if (texture.ptr)
|
||||
static_cast<CCWGPUTexture *>(texture.ptr)->stamp();
|
||||
});
|
||||
|
||||
bindGroupMap.insert(std::make_pair(_hash, BindGroupCache{this, _gpuBindGroupObj->bindgroup, _bornHash}));
|
||||
// CCWGPUDevice::getInstance()->destroyLater(_gpuBindGroupObj->bindgroup);
|
||||
} else {
|
||||
_gpuBindGroupObj->bindgroup = static_cast<WGPUBindGroup>(iter->second.bindGroup);
|
||||
_bornHash = iter->second.bornHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CCWGPUDescriptorSet::dynamicOffsetCount() const {
|
||||
return _dynamicOffsetNum;
|
||||
}
|
||||
|
||||
void *CCWGPUDescriptorSet::defaultBindGroup() {
|
||||
CCWGPUDeviceObject *deviceObj = CCWGPUDevice::getInstance()->gpuDeviceObject();
|
||||
|
||||
if (!dftBindGroup) {
|
||||
CCWGPUBuffer *buffer = deviceObj->defaultResources.uniformBuffer;
|
||||
WGPUBindGroupEntry bufferEntry = {
|
||||
.binding = 0,
|
||||
.buffer = buffer->gpuBufferObject()->wgpuBuffer,
|
||||
.offset = buffer->getOffset(),
|
||||
.size = buffer->getSize(),
|
||||
};
|
||||
|
||||
WGPUBindGroupDescriptor bindGroupDesc = {
|
||||
.nextInChain = nullptr,
|
||||
.label = "defaultBindGroup",
|
||||
.layout = static_cast<WGPUBindGroupLayout>(CCWGPUDescriptorSetLayout::defaultBindGroupLayout()),
|
||||
.entryCount = 1,
|
||||
.entries = &bufferEntry,
|
||||
};
|
||||
dftBindGroup = wgpuDeviceCreateBindGroup(deviceObj->wgpuDevice, &bindGroupDesc);
|
||||
}
|
||||
return dftBindGroup;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
96
cocos/renderer/gfx-wgpu/WGPUDescriptorSet.h
Normal file
96
cocos/renderer/gfx-wgpu/WGPUDescriptorSet.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
#include "gfx-base/GFXDescriptorSet.h"
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUBindGroupObject;
|
||||
|
||||
struct WGPUGPUDescriptor {
|
||||
DescriptorType type = DescriptorType::UNKNOWN;
|
||||
Buffer *buffer = nullptr;
|
||||
Texture *texture = nullptr;
|
||||
Sampler *sampler = nullptr;
|
||||
};
|
||||
using CCWGPUGPUDescriptorList = ccstd::vector<WGPUGPUDescriptor>;
|
||||
|
||||
// web interface
|
||||
struct CCWGPUGPUDescriptorSetObject {
|
||||
CCWGPUGPUDescriptorList gpuDescriptors;
|
||||
ccstd::vector<uint32_t> descriptorIndices;
|
||||
};
|
||||
|
||||
class CCWGPUDescriptorSet final : public DescriptorSet {
|
||||
public:
|
||||
CCWGPUDescriptorSet();
|
||||
~CCWGPUDescriptorSet();
|
||||
|
||||
inline CCWGPUBindGroupObject *gpuBindGroupObject() { return _gpuBindGroupObj; }
|
||||
inline const std::map<uint8_t, uint8_t> &dynamicOffsets() { return _dynamicOffsets; }
|
||||
|
||||
void update() override;
|
||||
void forceUpdate() override {
|
||||
_isDirty = true;
|
||||
update();
|
||||
};
|
||||
|
||||
void prune(ccstd::vector<uint8_t> bindings);
|
||||
uint8_t dynamicOffsetCount() const;
|
||||
void prepare();
|
||||
ccstd::hash_t getHash() { return _bornHash; }
|
||||
|
||||
static void *defaultBindGroup();
|
||||
static void clearCache();
|
||||
|
||||
std::string label;
|
||||
|
||||
inline void setLayout(const DescriptorSetLayout *layout) { _layout = layout; }
|
||||
|
||||
inline const CCWGPUGPUDescriptorSetObject gpuDescriptors() const { return *_gpuDescriptorObj; }
|
||||
void setGpuDescriptors(DescriptorSet *set);
|
||||
|
||||
protected:
|
||||
void doInit(const DescriptorSetInfo &info) override;
|
||||
void doDestroy() override;
|
||||
ccstd::hash_t hash() const;
|
||||
|
||||
CCWGPUBindGroupObject *_gpuBindGroupObj = nullptr;
|
||||
CCWGPUGPUDescriptorSetObject *_gpuDescriptorObj = nullptr;
|
||||
// dynamic offsets, inuse ? 1 : 0;
|
||||
std::map<uint8_t, uint8_t> _dynamicOffsets;
|
||||
uint32_t _dynamicOffsetNum{0};
|
||||
ccstd::hash_t _hash{0};
|
||||
ccstd::hash_t _bornHash{0}; // hash when created, this relate to reuse bindgroup layout
|
||||
std::function<bool(uint32_t)> _bindingSatisfied;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
283
cocos/renderer/gfx-wgpu/WGPUDescriptorSetLayout.cpp
Normal file
283
cocos/renderer/gfx-wgpu/WGPUDescriptorSetLayout.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUDescriptorSetLayout.h"
|
||||
#include <emscripten/html5_webgpu.h>
|
||||
#include <algorithm>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include "WGPUBuffer.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUSampler.h"
|
||||
#include "WGPUTexture.h"
|
||||
#include "WGPUUtils.h"
|
||||
#include "base/Assertf.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
WGPUBindGroupLayout dftBindgroupLayout = wgpuDefaultHandle;
|
||||
|
||||
ccstd::unordered_map<ccstd::hash_t, WGPUBindGroupLayout> layoutPool;
|
||||
|
||||
ccstd::hash_t hash(const ccstd::vector<WGPUBindGroupLayoutEntry> &entries) {
|
||||
ccstd::hash_t hash = 9527;
|
||||
ccstd::hash_combine(hash, entries.size());
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
ccstd::hash_combine(hash, i);
|
||||
ccstd::hash_combine(hash, entries[i].binding);
|
||||
ccstd::hash_combine(hash, entries[i].visibility);
|
||||
if (entries[i].buffer.type != WGPUBufferBindingType_Undefined) {
|
||||
ccstd::hash_combine(hash, entries[i].buffer.type);
|
||||
ccstd::hash_combine(hash, entries[i].buffer.hasDynamicOffset);
|
||||
ccstd::hash_combine(hash, entries[i].buffer.minBindingSize);
|
||||
}
|
||||
if (entries[i].sampler.type != WGPUSamplerBindingType_Undefined) {
|
||||
ccstd::hash_combine(hash, entries[i].sampler.type);
|
||||
}
|
||||
if (entries[i].texture.sampleType != WGPUTextureSampleType_Undefined) {
|
||||
ccstd::hash_combine(hash, entries[i].texture.sampleType);
|
||||
ccstd::hash_combine(hash, entries[i].texture.viewDimension);
|
||||
ccstd::hash_combine(hash, entries[i].texture.multisampled);
|
||||
}
|
||||
if (entries[i].storageTexture.access != WGPUStorageTextureAccess_Undefined) {
|
||||
ccstd::hash_combine(hash, entries[i].storageTexture.access);
|
||||
ccstd::hash_combine(hash, entries[i].storageTexture.format);
|
||||
ccstd::hash_combine(hash, entries[i].storageTexture.viewDimension);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool checkInUse(uint8_t binding, const ccstd::set<uint8_t> &bindingInUse, bool samplerBinding) {
|
||||
bool res = bindingInUse.find(binding) != bindingInUse.end();
|
||||
if (!res && samplerBinding) {
|
||||
res |= bindingInUse.find(binding - CC_WGPU_MAX_ATTACHMENTS) != bindingInUse.end();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
CCWGPUDescriptorSetLayout::CCWGPUDescriptorSetLayout() : DescriptorSetLayout() {
|
||||
}
|
||||
|
||||
CCWGPUDescriptorSetLayout::~CCWGPUDescriptorSetLayout() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSetLayout::doInit(const DescriptorSetLayoutInfo &info) {
|
||||
_gpuLayoutEntryObj = ccnew CCWGPUBindGroupLayoutObject;
|
||||
(void)defaultBindGroupLayout();
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSetLayout::updateBufferLayout(uint8_t index, const CCWGPUBuffer *buffer, AccessFlags flags) {
|
||||
WGPUBindGroupLayoutEntry bufferEntry{};
|
||||
bufferEntry.binding = _bindings[index].binding;
|
||||
bufferEntry.visibility = toWGPUShaderStageFlag(_bindings[index].stageFlags);
|
||||
|
||||
CC_ASSERT(buffer);
|
||||
|
||||
WGPUBufferBindingLayout bufferLayout{};
|
||||
bool storageFlag = hasFlag(_bindings[index].descriptorType, DescriptorType::STORAGE_BUFFER | DescriptorType::DYNAMIC_STORAGE_BUFFER);
|
||||
if (storageFlag) {
|
||||
bufferLayout.type = flags > AccessFlagBit::PRESENT ? WGPUBufferBindingType_Storage : WGPUBufferBindingType_ReadOnlyStorage;
|
||||
} else {
|
||||
bufferLayout.type = WGPUBufferBindingType_Uniform;
|
||||
}
|
||||
bufferLayout.hasDynamicOffset = hasAnyFlags(_bindings[index].descriptorType, DescriptorType::DYNAMIC_STORAGE_BUFFER | DescriptorType::DYNAMIC_UNIFORM_BUFFER);
|
||||
|
||||
bufferEntry.buffer = bufferLayout;
|
||||
_gpuLayoutEntryObj->bindGroupLayoutEntries[bufferEntry.binding] = bufferEntry;
|
||||
}
|
||||
|
||||
namespace {
|
||||
WGPUTextureFormat formatTraits(const CCWGPUTexture *texture, uint32_t plane) {
|
||||
if (texture->getFormat() == Format::DEPTH_STENCIL) {
|
||||
return plane ? WGPUTextureFormat_Stencil8 : WGPUTextureFormat_Depth24Plus;
|
||||
}
|
||||
return toWGPUTextureFormat(texture->getFormat());
|
||||
}
|
||||
|
||||
WGPUTextureSampleType sampletypeTraits(const CCWGPUTexture *texture, uint32_t plane) {
|
||||
if (texture->getFormat() == Format::DEPTH_STENCIL) {
|
||||
return plane ? WGPUTextureSampleType_Uint : WGPUTextureSampleType_UnfilterableFloat;
|
||||
}
|
||||
return textureSampleTypeTrait(texture->getFormat());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void CCWGPUDescriptorSetLayout::updateSampledTextureLayout(uint8_t index, const CCWGPUTexture *texture, uint32_t plane) {
|
||||
WGPUBindGroupLayoutEntry textureEntry{};
|
||||
textureEntry.binding = _bindings[index].binding;
|
||||
textureEntry.visibility = toWGPUShaderStageFlag(_bindings[index].stageFlags);
|
||||
|
||||
CC_ASSERT(texture);
|
||||
|
||||
WGPUTextureBindingLayout textureLayout{};
|
||||
textureLayout.sampleType = sampletypeTraits(texture, plane); // textureSampleTypeTrait(texture->getFormat());
|
||||
const CCWGPUTexture *ccTex = static_cast<const CCWGPUTexture *>(texture->isTextureView() ? texture->getViewInfo().texture : texture);
|
||||
TextureType type = ccTex->getViewInfo().type;
|
||||
textureLayout.viewDimension = toWGPUTextureViewDimension(type);
|
||||
textureLayout.multisampled = ccTex->getInfo().samples != SampleCount::X1;
|
||||
textureEntry.texture = textureLayout;
|
||||
_gpuLayoutEntryObj->bindGroupLayoutEntries[textureEntry.binding] = textureEntry;
|
||||
}
|
||||
void CCWGPUDescriptorSetLayout::updateStorageTextureLayout(uint8_t index, const CCWGPUTexture *texture, uint32_t plane) {
|
||||
WGPUBindGroupLayoutEntry textureEntry{};
|
||||
textureEntry.binding = _bindings[index].binding;
|
||||
textureEntry.visibility = toWGPUShaderStageFlag(_bindings[index].stageFlags);
|
||||
CC_ASSERT(texture);
|
||||
WGPUStorageTextureBindingLayout storageTextureLayout{};
|
||||
storageTextureLayout.access = WGPUStorageTextureAccess::WGPUStorageTextureAccess_WriteOnly;
|
||||
storageTextureLayout.format = formatTraits(texture, plane);
|
||||
TextureType type = texture->isTextureView() ? texture->getViewInfo().type : texture->getInfo().type;
|
||||
storageTextureLayout.viewDimension = toWGPUTextureViewDimension(type);
|
||||
textureEntry.storageTexture = storageTextureLayout;
|
||||
_gpuLayoutEntryObj->bindGroupLayoutEntries[textureEntry.binding] = textureEntry;
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSetLayout::updateSamplerLayout(uint8_t index, const CCWGPUSampler *sampler) {
|
||||
WGPUBindGroupLayoutEntry samplerEntry{};
|
||||
samplerEntry.binding = _bindings[index].binding + CC_WGPU_MAX_ATTACHMENTS;
|
||||
samplerEntry.visibility = toWGPUShaderStageFlag(_bindings[index].stageFlags);
|
||||
|
||||
CC_ASSERT(sampler);
|
||||
|
||||
WGPUSamplerBindingLayout samplerLayout{};
|
||||
const SamplerInfo &info = sampler->getInfo();
|
||||
if ((info.minFilter == Filter::POINT || info.minFilter == Filter::NONE) &&
|
||||
(info.magFilter == Filter::POINT || info.magFilter == Filter::NONE) &&
|
||||
(info.mipFilter == Filter::POINT || info.mipFilter == Filter::NONE)) {
|
||||
samplerLayout.type = WGPUSamplerBindingType::WGPUSamplerBindingType_NonFiltering;
|
||||
} else {
|
||||
samplerLayout.type = WGPUSamplerBindingType::WGPUSamplerBindingType_Filtering;
|
||||
}
|
||||
samplerEntry.sampler = samplerLayout;
|
||||
|
||||
_gpuLayoutEntryObj->bindGroupLayoutEntries[samplerEntry.binding] = samplerEntry;
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSetLayout::print() const {
|
||||
size_t hashVal = _hash;
|
||||
printf("\npr this %p %p %zu\n", _gpuLayoutEntryObj, this, hashVal);
|
||||
const auto &entries = _gpuLayoutEntryObj->bindGroupLayoutEntries;
|
||||
for (const auto &[bd, entry] : entries) {
|
||||
if ((entry.buffer.type != WGPUBufferBindingType_Undefined) +
|
||||
(entry.sampler.type != WGPUSamplerBindingType_Undefined) +
|
||||
(entry.texture.sampleType != WGPUTextureSampleType_Undefined) +
|
||||
(entry.storageTexture.access != WGPUStorageTextureAccess_Undefined) !=
|
||||
1) {
|
||||
printf("******missing %d, %d, %d, %d, %d\n", entry.binding, entry.buffer.type, entry.sampler.type, entry.texture.sampleType, entry.storageTexture.access);
|
||||
}
|
||||
printf("%d, %d, %d\n", entry.binding, entry.visibility, static_cast<int>(entries.size()));
|
||||
if (entry.buffer.type != WGPUBufferBindingType_Undefined) {
|
||||
printf("b %d %d %llu\n", entry.buffer.type, entry.buffer.hasDynamicOffset ? 1 : 0, entry.buffer.minBindingSize);
|
||||
}
|
||||
if (entry.sampler.type != WGPUSamplerBindingType_Undefined) {
|
||||
printf("s %d\n", entry.sampler.type);
|
||||
}
|
||||
if (entry.texture.sampleType != WGPUTextureSampleType_Undefined) {
|
||||
printf("t %d %d %d\n", entry.texture.sampleType, entry.texture.viewDimension, entry.texture.multisampled ? 1 : 0);
|
||||
}
|
||||
if (entry.storageTexture.access != WGPUStorageTextureAccess_Undefined) {
|
||||
printf("st %d %d %d\n", entry.storageTexture.access, entry.storageTexture.format, entry.storageTexture.viewDimension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSetLayout::prepare(ccstd::set<uint8_t> &bindingInUse, bool forceUpdate) {
|
||||
ccstd::vector<WGPUBindGroupLayoutEntry> bindGroupLayoutEntries{};
|
||||
bindGroupLayoutEntries.reserve(_gpuLayoutEntryObj->bindGroupLayoutEntries.size());
|
||||
for (const auto &[bd, layoutEntry] : _gpuLayoutEntryObj->bindGroupLayoutEntries) {
|
||||
if(checkInUse(static_cast<uint8_t>(bd), bindingInUse, layoutEntry.sampler.type != WGPUSamplerBindingType_Undefined)) {
|
||||
bindGroupLayoutEntries.emplace_back(layoutEntry);
|
||||
}
|
||||
}
|
||||
|
||||
_hash = hash(bindGroupLayoutEntries);
|
||||
auto iter = layoutPool.find(_hash);
|
||||
if (iter != layoutPool.end()) {
|
||||
_gpuLayoutEntryObj->bindGroupLayout = iter->second;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &entries = bindGroupLayoutEntries;
|
||||
if (entries.empty()) {
|
||||
_gpuLayoutEntryObj->bindGroupLayout = dftBindgroupLayout;
|
||||
} else {
|
||||
WGPUBindGroupLayoutDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = "",//std::to_string(_hash).c_str(),
|
||||
.entryCount = entries.size(),
|
||||
.entries = entries.data(),
|
||||
};
|
||||
_gpuLayoutEntryObj->bindGroupLayout = wgpuDeviceCreateBindGroupLayout(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
printf("create new bglayout\n");
|
||||
}
|
||||
layoutPool.insert({_hash, _gpuLayoutEntryObj->bindGroupLayout});
|
||||
}
|
||||
|
||||
void *CCWGPUDescriptorSetLayout::getBindGroupLayoutByHash(ccstd::hash_t hash) {
|
||||
void *ret = nullptr;
|
||||
auto iter = layoutPool.find(hash);
|
||||
if (iter != layoutPool.end()) {
|
||||
ret = iter->second;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *CCWGPUDescriptorSetLayout::defaultBindGroupLayout() {
|
||||
if (!dftBindgroupLayout) {
|
||||
// default bindgroupLayout: for empty set
|
||||
WGPUBindGroupLayoutEntry layout = {
|
||||
.nextInChain = nullptr,
|
||||
.binding = 0,
|
||||
.visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment | WGPUShaderStage_Compute,
|
||||
.buffer = {nullptr, WGPUBufferBindingType::WGPUBufferBindingType_Uniform, false, 0},
|
||||
};
|
||||
|
||||
WGPUBindGroupLayoutDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = "defaultBindgroupLayout",
|
||||
.entryCount = 1,
|
||||
.entries = &layout,
|
||||
};
|
||||
dftBindgroupLayout = wgpuDeviceCreateBindGroupLayout(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
}
|
||||
return dftBindgroupLayout;
|
||||
}
|
||||
|
||||
void CCWGPUDescriptorSetLayout::doDestroy() {
|
||||
if (_gpuLayoutEntryObj) {
|
||||
delete _gpuLayoutEntryObj;
|
||||
_gpuLayoutEntryObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
77
cocos/renderer/gfx-wgpu/WGPUDescriptorSetLayout.h
Normal file
77
cocos/renderer/gfx-wgpu/WGPUDescriptorSetLayout.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "base/std/container/set.h"
|
||||
#include "gfx-base/GFXDescriptorSetLayout.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUBindGroupLayoutObject;
|
||||
class CCWGPUTexture;
|
||||
class CCWGPUBuffer;
|
||||
class CCWGPUSampler;
|
||||
|
||||
class CCWGPUDescriptorSetLayout final : public DescriptorSetLayout {
|
||||
public:
|
||||
CCWGPUDescriptorSetLayout();
|
||||
~CCWGPUDescriptorSetLayout();
|
||||
|
||||
inline CCWGPUBindGroupLayoutObject *gpuLayoutEntryObject() { return _gpuLayoutEntryObj; }
|
||||
|
||||
void updateBufferLayout(uint8_t index, const CCWGPUBuffer *buffer, AccessFlags flags);
|
||||
void updateSampledTextureLayout(uint8_t index, const CCWGPUTexture *texture, uint32_t plane = 0);
|
||||
void updateStorageTextureLayout(uint8_t index, const CCWGPUTexture *texture, uint32_t plane = 0);
|
||||
void updateSamplerLayout(uint8_t index, const CCWGPUSampler *sampler);
|
||||
|
||||
inline void setBindings(const DescriptorSetLayoutBindingList &list) { _bindings.assign(list.begin(), list.end()); }
|
||||
inline void setBindingIndices(const ccstd::vector<uint32_t> &list) { _bindingIndices.assign(list.begin(), list.end()); }
|
||||
inline void setDescriptorIndices(const ccstd::vector<uint32_t> &indices) { _descriptorIndices.assign(indices.begin(), indices.end()); }
|
||||
|
||||
void prepare(ccstd::set<uint8_t> &bindingInUse, bool forceUpdate = false);
|
||||
|
||||
static void *defaultBindGroupLayout();
|
||||
static void *getBindGroupLayoutByHash(ccstd::hash_t hash);
|
||||
|
||||
void print() const;
|
||||
|
||||
ccstd::hash_t getHash() {
|
||||
return _hash;
|
||||
}
|
||||
|
||||
protected:
|
||||
void doInit(const DescriptorSetLayoutInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
ccstd::hash_t _hash{0};
|
||||
|
||||
CCWGPUBindGroupLayoutObject *_gpuLayoutEntryObj = nullptr;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
750
cocos/renderer/gfx-wgpu/WGPUDevice.cpp
Normal file
750
cocos/renderer/gfx-wgpu/WGPUDevice.cpp
Normal file
@@ -0,0 +1,750 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUDevice.h"
|
||||
#include <emscripten/val.h>
|
||||
#include <numeric>
|
||||
#include "../../base/threading/Semaphore.h"
|
||||
#include "WGPUBuffer.h"
|
||||
#include "WGPUCommandBuffer.h"
|
||||
#include "WGPUDescriptorSet.h"
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUExports.h"
|
||||
#include "WGPUFrameBuffer.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUPipelineLayout.h"
|
||||
#include "WGPUPipelineState.h"
|
||||
#include "WGPUQueryPool.h"
|
||||
#include "WGPUQueue.h"
|
||||
#include "WGPURenderPass.h"
|
||||
#include "WGPUSampler.h"
|
||||
#include "WGPUShader.h"
|
||||
#include "WGPUSwapchain.h"
|
||||
#include "WGPUUtils.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
struct BufferMapData {
|
||||
Semaphore *semaphore = nullptr;
|
||||
WGPUBuffer buffer = wgpuDefaultHandle;
|
||||
emscripten::val *retBuffer = nullptr;
|
||||
uint64_t size = 0;
|
||||
bool finished = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void onAdapterGot(WGPURequestAdapterStatus status, WGPUAdapter adapter, char const *message, void *userdata) {
|
||||
if (message) {
|
||||
printf("onAdapterGot: %s\n", message);
|
||||
}
|
||||
if (status == WGPURequestAdapterStatus_Success) {
|
||||
auto *device = static_cast<CCWGPUDevice *>(userdata);
|
||||
device->gpuDeviceObject()->instance.wgpuAdapter = adapter;
|
||||
device->initConfigs();
|
||||
device->initLimits();
|
||||
} else {
|
||||
printf("onAdapterGot: failed to get adapter\n");
|
||||
}
|
||||
}
|
||||
|
||||
CCWGPUDevice *CCWGPUDevice::instance = nullptr;
|
||||
|
||||
CCWGPUDevice *CCWGPUDevice::getInstance() {
|
||||
// if JS
|
||||
if (!instance) {
|
||||
instance = ccnew CCWGPUDevice();
|
||||
}
|
||||
// endif
|
||||
return instance;
|
||||
}
|
||||
|
||||
CCWGPUDevice::CCWGPUDevice() : Device() {
|
||||
_api = API::WEBGPU;
|
||||
_deviceName = "WebGPU";
|
||||
_caps.clipSpaceMinZ = 0.0F;
|
||||
_caps.screenSpaceSignY = -1.0F;
|
||||
_caps.clipSpaceSignY = 1.0F;
|
||||
|
||||
// Sept 6th 2022: ems getLimits not implemented
|
||||
_caps.uboOffsetAlignment = 256;
|
||||
_caps.uboOffsetAlignment = 256;
|
||||
_caps.maxVertexUniformVectors = 256;
|
||||
_caps.maxFragmentUniformVectors = 256;
|
||||
|
||||
_caps.maxComputeSharedMemorySize = 32768;
|
||||
_caps.maxComputeWorkGroupInvocations = 256;
|
||||
_caps.maxComputeWorkGroupSize = {65535, 65535, 65535};
|
||||
_caps.maxComputeWorkGroupCount = {256, 256, 64};
|
||||
|
||||
instance = this;
|
||||
}
|
||||
|
||||
CCWGPUDevice::~CCWGPUDevice() {
|
||||
doDestroy();
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
bool CCWGPUDevice::doInit(const DeviceInfo &info) {
|
||||
_gpuDeviceObj = ccnew CCWGPUDeviceObject;
|
||||
_gpuDeviceObj->wgpuDevice = emscripten_webgpu_get_device();
|
||||
_gpuDeviceObj->wgpuQueue = wgpuDeviceGetQueue(_gpuDeviceObj->wgpuDevice);
|
||||
|
||||
_gpuDeviceObj->defaultResources.uniformBuffer = CCWGPUBuffer::defaultUniformBuffer();
|
||||
_gpuDeviceObj->defaultResources.storageBuffer = CCWGPUBuffer::defaultStorageBuffer();
|
||||
_gpuDeviceObj->defaultResources.commonTexture = CCWGPUTexture::defaultCommonTexture();
|
||||
_gpuDeviceObj->defaultResources.storageTexture = CCWGPUTexture::defaultStorageTexture();
|
||||
_gpuDeviceObj->defaultResources.filterableSampler = CCWGPUSampler::defaultFilterableSampler();
|
||||
_gpuDeviceObj->defaultResources.unfilterableSampler = CCWGPUSampler::defaultUnfilterableSampler();
|
||||
|
||||
QueueInfo queueInfo = {
|
||||
.type = QueueType::GRAPHICS,
|
||||
};
|
||||
_queue = this->Device::createQueue(queueInfo);
|
||||
|
||||
CommandBufferInfo cmdInfo = {
|
||||
.queue = _queue,
|
||||
.type = CommandBufferType::PRIMARY,
|
||||
};
|
||||
_cmdBuff = this->Device::createCommandBuffer(cmdInfo);
|
||||
_gpuDeviceObj->instance.wgpuInstance = wgpuCreateInstance({});
|
||||
|
||||
#ifdef CC_WGPU_WASM
|
||||
WGPUSurfaceDescriptorFromCanvasHTMLSelector canvDesc = {};
|
||||
canvDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
|
||||
canvDesc.selector = "canvas";
|
||||
|
||||
WGPUSurfaceDescriptor surfDesc = {};
|
||||
surfDesc.nextInChain = reinterpret_cast<WGPUChainedStruct *>(&canvDesc);
|
||||
_gpuDeviceObj->instance.wgpuSurface = wgpuInstanceCreateSurface(_gpuDeviceObj->instance.wgpuInstance, &surfDesc);
|
||||
|
||||
#elif defined(CC_WGPU_DAWN)
|
||||
_gpuDeviceObj->instance.wgpuInstance = wgpuCreateInstance({});
|
||||
WGPUSurfaceDescriptor sufaceDesc = {
|
||||
.label = "DAWNSurface",
|
||||
};
|
||||
_gpuDeviceObj->instance.wgpuSurface = wgpuInstanceCreateSurface(_gpuDeviceObj->instance.wgpuInstance, &sufaceDesc);
|
||||
|
||||
#endif
|
||||
WGPURequestAdapterOptions options = {
|
||||
.compatibleSurface = _gpuDeviceObj->instance.wgpuSurface,
|
||||
.powerPreference = WGPUPowerPreference_LowPower,
|
||||
};
|
||||
|
||||
wgpuInstanceRequestAdapter(_gpuDeviceObj->instance.wgpuInstance, &options, onAdapterGot, this);
|
||||
|
||||
// auto bufferRecycleFunc = [this](WGPUBuffer buffer) {
|
||||
// _recycleBin[getCurrentFrameIndex()].bufferBin.collect(buffer);
|
||||
// };
|
||||
// for (size_t i = 0; i < CC_WGPU_MAX_FRAME_COUNT; ++i) {
|
||||
// _stagingBuffers[i] = new CCWGPUStagingBuffer(_gpuDeviceObj->wgpuDevice, bufferRecycleFunc);
|
||||
// }
|
||||
|
||||
initFeatures();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCWGPUDevice::doDestroy() {
|
||||
if (_gpuDeviceObj) {
|
||||
if (_gpuDeviceObj->defaultResources.uniformBuffer) {
|
||||
delete _gpuDeviceObj->defaultResources.uniformBuffer;
|
||||
}
|
||||
if (_gpuDeviceObj->defaultResources.storageBuffer) {
|
||||
delete _gpuDeviceObj->defaultResources.storageBuffer;
|
||||
}
|
||||
if (_gpuDeviceObj->defaultResources.commonTexture) {
|
||||
delete _gpuDeviceObj->defaultResources.commonTexture;
|
||||
}
|
||||
if (_gpuDeviceObj->defaultResources.storageTexture) {
|
||||
delete _gpuDeviceObj->defaultResources.storageTexture;
|
||||
}
|
||||
if (_gpuDeviceObj->defaultResources.filterableSampler) {
|
||||
delete _gpuDeviceObj->defaultResources.filterableSampler;
|
||||
}
|
||||
if (_gpuDeviceObj->defaultResources.unfilterableSampler) {
|
||||
delete _gpuDeviceObj->defaultResources.unfilterableSampler;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < CC_WGPU_MAX_FRAME_COUNT; ++i) {
|
||||
_recycleBin[i].bufferBin.purge();
|
||||
_recycleBin[i].textureBin.purge();
|
||||
_recycleBin[i].queryBin.purge();
|
||||
}
|
||||
|
||||
if (_gpuDeviceObj->wgpuQueue) {
|
||||
wgpuQueueRelease(_gpuDeviceObj->wgpuQueue);
|
||||
}
|
||||
if (_gpuDeviceObj->instance.wgpuSurface) {
|
||||
wgpuSurfaceRelease(_gpuDeviceObj->instance.wgpuSurface);
|
||||
}
|
||||
if (_gpuDeviceObj->instance.wgpuInstance) {
|
||||
wgpuInstanceRelease(_gpuDeviceObj->instance.wgpuInstance);
|
||||
}
|
||||
if (_gpuDeviceObj->instance.wgpuAdapter) {
|
||||
wgpuAdapterRelease(_gpuDeviceObj->instance.wgpuAdapter);
|
||||
}
|
||||
if (_gpuDeviceObj->wgpuDevice) {
|
||||
wgpuDeviceRelease(_gpuDeviceObj->wgpuDevice);
|
||||
}
|
||||
|
||||
delete _gpuDeviceObj;
|
||||
_gpuDeviceObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Swapchain *CCWGPUDevice::createSwapchain() {
|
||||
return ccnew CCWGPUSwapchain(this);
|
||||
}
|
||||
|
||||
Queue *CCWGPUDevice::createQueue() {
|
||||
return ccnew CCWGPUQueue;
|
||||
}
|
||||
|
||||
Buffer *CCWGPUDevice::createBuffer() {
|
||||
return ccnew CCWGPUBuffer;
|
||||
}
|
||||
|
||||
Texture *CCWGPUDevice::createTexture() {
|
||||
return ccnew CCWGPUTexture;
|
||||
}
|
||||
|
||||
Shader *CCWGPUDevice::createShader() {
|
||||
return ccnew CCWGPUShader;
|
||||
}
|
||||
|
||||
InputAssembler *CCWGPUDevice::createInputAssembler() {
|
||||
return ccnew CCWGPUInputAssembler;
|
||||
}
|
||||
|
||||
RenderPass *CCWGPUDevice::createRenderPass() {
|
||||
return ccnew CCWGPURenderPass;
|
||||
}
|
||||
|
||||
Framebuffer *CCWGPUDevice::createFramebuffer() {
|
||||
return ccnew CCWGPUFramebuffer;
|
||||
}
|
||||
|
||||
DescriptorSet *CCWGPUDevice::createDescriptorSet() {
|
||||
return ccnew CCWGPUDescriptorSet;
|
||||
}
|
||||
|
||||
DescriptorSetLayout *CCWGPUDevice::createDescriptorSetLayout() {
|
||||
return ccnew CCWGPUDescriptorSetLayout;
|
||||
}
|
||||
|
||||
PipelineLayout *CCWGPUDevice::createPipelineLayout() {
|
||||
return ccnew CCWGPUPipelineLayout;
|
||||
}
|
||||
|
||||
PipelineState *CCWGPUDevice::createPipelineState() {
|
||||
return ccnew CCWGPUPipelineState;
|
||||
}
|
||||
|
||||
CommandBuffer *CCWGPUDevice::createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) {
|
||||
return ccnew CCWGPUCommandBuffer;
|
||||
}
|
||||
|
||||
Shader *CCWGPUDevice::createShader(const ShaderInfo &info, const std::vector<std::vector<uint32_t>> &spvData) {
|
||||
auto *shader = ccnew CCWGPUShader;
|
||||
shader->initialize(info, spvData);
|
||||
return shader;
|
||||
}
|
||||
|
||||
void CCWGPUDevice::copyBuffersToTexture(const uint8_t *const *buffers, Texture *dst, const BufferTextureCopy *regions, uint count) {
|
||||
Format dstFormat = dst->getFormat();
|
||||
uint32_t pxSize = GFX_FORMAT_INFOS[static_cast<uint>(dstFormat)].size;
|
||||
auto *texture = static_cast<CCWGPUTexture *>(dst);
|
||||
auto blockSize = formatAlignment(dstFormat);
|
||||
|
||||
auto *ccTexture = static_cast<CCWGPUTexture *>(texture);
|
||||
if (ccTexture->isTextureView()) {
|
||||
ccTexture = static_cast<CCWGPUTexture *>(ccTexture->getViewInfo().texture);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const auto ®ion = regions[i];
|
||||
auto bufferPixelWidth = region.buffStride > 0 ? region.buffStride : region.texExtent.width;
|
||||
auto bufferPixelHeight = region.buffTexHeight > 0 ? region.buffTexHeight : region.texExtent.height;
|
||||
auto bytesPerRow = formatSize(dstFormat, region.texExtent.width, 1, 1);
|
||||
auto bufferBytesPerRow = formatSize(dstFormat, bufferPixelWidth, 1, 1);
|
||||
auto bufferBytesPerImageSlice = formatSize(dstFormat, bufferPixelWidth, bufferPixelHeight, 1);
|
||||
auto bufferBytesPerImageLayer = formatSize(dstFormat, bufferPixelWidth, bufferPixelHeight, region.texExtent.depth);
|
||||
auto targetWidth = region.texExtent.width == 0 ? 0 : utils::alignTo(region.texExtent.width, blockSize.first);
|
||||
auto targetHeight = region.texExtent.height == 0 ? 0 : utils::alignTo(region.texExtent.height, blockSize.second);
|
||||
|
||||
// it's buffer data layout
|
||||
WGPUTextureDataLayout texDataLayout = {
|
||||
.offset = 0,
|
||||
.bytesPerRow = bufferBytesPerRow,
|
||||
.rowsPerImage = bufferPixelHeight,
|
||||
};
|
||||
|
||||
bool compactInWidth = bufferPixelWidth == region.texExtent.width;
|
||||
for (size_t l = region.texSubres.baseArrayLayer; l < region.texSubres.layerCount + region.texSubres.baseArrayLayer; ++l) {
|
||||
for (size_t d = region.texOffset.z; d < region.texExtent.depth + region.texOffset.z; ++d) {
|
||||
if (compactInWidth) {
|
||||
auto *srcData = buffers[i] + region.buffOffset + (l - region.texSubres.baseArrayLayer) * bufferBytesPerImageLayer + (d - region.texOffset.z) * bufferBytesPerImageSlice;
|
||||
WGPUImageCopyTexture imageCopyTexture = {
|
||||
.texture = ccTexture->gpuTextureObject()->wgpuTexture,
|
||||
.mipLevel = region.texSubres.mipLevel,
|
||||
.origin = WGPUOrigin3D{
|
||||
static_cast<uint32_t>(region.texOffset.x),
|
||||
static_cast<uint32_t>(region.texOffset.y),
|
||||
static_cast<uint32_t>(l)},
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = targetWidth,
|
||||
.height = targetHeight,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
|
||||
wgpuQueueWriteTexture(_gpuDeviceObj->wgpuQueue, &imageCopyTexture, srcData, bufferBytesPerImageSlice, &texDataLayout, &extent);
|
||||
} else {
|
||||
for (size_t h = region.texOffset.y; h < region.texExtent.height + region.texOffset.y; h += blockSize.second) {
|
||||
auto *srcData = buffers[i] + region.buffOffset + (l - region.texSubres.baseArrayLayer) * bufferBytesPerImageLayer + (d - region.texOffset.z) * bufferBytesPerImageSlice +
|
||||
(h - region.texOffset.y) / blockSize.second * bufferBytesPerRow;
|
||||
WGPUImageCopyTexture imageCopyTexture = {
|
||||
.texture = ccTexture->gpuTextureObject()->wgpuTexture,
|
||||
.mipLevel = region.texSubres.mipLevel,
|
||||
.origin = WGPUOrigin3D{
|
||||
static_cast<uint32_t>(region.texOffset.x),
|
||||
static_cast<uint32_t>(h),
|
||||
static_cast<uint32_t>(l)},
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = targetWidth,
|
||||
.height = blockSize.second,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
|
||||
wgpuQueueWriteTexture(_gpuDeviceObj->wgpuQueue, &imageCopyTexture, srcData, bytesPerRow, &texDataLayout, &extent);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasFlag(ccTexture->getInfo().flags, TextureFlags::GEN_MIPMAP)) {
|
||||
genMipMap(ccTexture, 1, ccTexture->getInfo().levelCount - 1, l, _cmdBuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onQueueDone(WGPUQueueWorkDoneStatus status, void *userdata) {
|
||||
if (status == WGPUQueueWorkDoneStatus_Success) {
|
||||
auto *bufferMapData = static_cast<BufferMapData *>(userdata);
|
||||
// auto* mappedBuffer = wgpuBufferGetMappedRange(bufferMapData->buffer, 0, bufferMapData->size);
|
||||
auto *mappedBuffer = (uint8_t *)malloc(static_cast<uint32_t>(bufferMapData->size));
|
||||
*bufferMapData->retBuffer = emscripten::val(emscripten::typed_memory_view(bufferMapData->size, static_cast<uint8_t *>(mappedBuffer)));
|
||||
bufferMapData->finished = true;
|
||||
// memcpy(bufferMapData->dst, mappedBuffer, bufferMapData->size);
|
||||
}
|
||||
}
|
||||
|
||||
emscripten::val CCWGPUDevice::copyTextureToBuffers(Texture *src, const BufferTextureCopyList ®ions) {
|
||||
// auto *texture = static_cast<CCWGPUTexture *>(src);
|
||||
// Format dstFormat = src->getFormat();
|
||||
// uint32_t pxSize = GFX_FORMAT_INFOS[static_cast<uint32_t>(dstFormat)].size;
|
||||
// auto wgpuCommandEncoder = wgpuDeviceCreateCommandEncoder(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, nullptr);
|
||||
|
||||
// uint64_t size = std::accumulate(regions.begin(), regions.end(), 0, [pxSize](uint64_t initVal, const BufferTextureCopy &in) {
|
||||
// uint32_t bytesPerRow = (pxSize * in.texExtent.width + 255) / 256 * 256;
|
||||
// uint32_t bufferSize = bytesPerRow * in.texExtent.height * in.texExtent.depth;
|
||||
// return initVal + bufferSize;
|
||||
// });
|
||||
|
||||
// WGPUBufferDescriptor descriptor = {
|
||||
// .nextInChain = nullptr,
|
||||
// .label = nullptr,
|
||||
// .usage = WGPUBufferUsage_MapRead | WGPUBufferUsage_CopyDst,
|
||||
// .size = size,
|
||||
// .mappedAtCreation = false,
|
||||
// };
|
||||
|
||||
// WGPUBuffer buffer = wgpuDeviceCreateBuffer(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
// uint64_t offset = 0;
|
||||
// for (size_t i = 0; i < regions.size(); i++) {
|
||||
// uint32_t bytesPerRow = (pxSize * regions[i].texExtent.width + 255) / 256 * 256;
|
||||
// WGPUImageCopyTexture imageCopyTexture = {
|
||||
// .texture = texture->gpuTextureObject()->wgpuTexture,
|
||||
// .mipLevel = regions[i].texSubres.mipLevel,
|
||||
// .origin = WGPUOrigin3D{
|
||||
// static_cast<uint32_t>(regions[i].texOffset.x),
|
||||
// static_cast<uint32_t>(regions[i].texOffset.y),
|
||||
// static_cast<uint32_t>(regions[i].texOffset.z)},
|
||||
// .aspect = WGPUTextureAspect_All,
|
||||
// };
|
||||
|
||||
// WGPUTextureDataLayout texDataLayout = {
|
||||
// .offset = offset,
|
||||
// .bytesPerRow = bytesPerRow,
|
||||
// .rowsPerImage = regions[i].texExtent.height,
|
||||
// };
|
||||
// uint32_t bufferSize = pxSize * regions[i].texExtent.width * regions[i].texExtent.depth;
|
||||
// offset += bufferSize;
|
||||
|
||||
// WGPUImageCopyBuffer imageCopyBuffer = {
|
||||
// .layout = texDataLayout,
|
||||
// .buffer = buffer,
|
||||
// };
|
||||
|
||||
// WGPUExtent3D extent = {
|
||||
// .width = regions[i].texExtent.width,
|
||||
// .height = regions[i].texExtent.height,
|
||||
// .depthOrArrayLayers = regions[i].texExtent.depth,
|
||||
// };
|
||||
|
||||
// wgpuCommandEncoderCopyTextureToBuffer(wgpuCommandEncoder, &imageCopyTexture, &imageCopyBuffer, &extent);
|
||||
// }
|
||||
|
||||
// auto wgpuCommandBuffer = wgpuCommandEncoderFinish(wgpuCommandEncoder, nullptr);
|
||||
// wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &wgpuCommandBuffer);
|
||||
// printf("Q submit\n");
|
||||
// Semaphore sem{0};
|
||||
// BufferMapData *bufferMapData = ccnew BufferMapData{
|
||||
// &sem,
|
||||
// buffer,
|
||||
// nullptr,
|
||||
// size,
|
||||
// false,
|
||||
// };
|
||||
|
||||
// wgpuQueueOnSubmittedWorkDone(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, onQueueDone, bufferMapData);
|
||||
|
||||
// while (!bufferMapData->finished) {
|
||||
// ;
|
||||
// }
|
||||
// // wgpuBufferRelease(buffer);
|
||||
// return *bufferMapData->retBuffer;
|
||||
return emscripten::val::undefined();
|
||||
}
|
||||
|
||||
void CCWGPUDevice::copyTextureToBuffers(Texture *src, uint8_t *const *buffers, const BufferTextureCopy *region, uint32_t count) {
|
||||
}
|
||||
|
||||
void CCWGPUDevice::acquire(Swapchain *const *swapchains, uint32_t count) {
|
||||
for (auto *swapchain : _swapchains) {
|
||||
swapchain->update();
|
||||
}
|
||||
}
|
||||
|
||||
QueryPool *CCWGPUDevice::createQueryPool() {
|
||||
return ccnew CCWGPUQueryPool;
|
||||
}
|
||||
|
||||
Sampler *CCWGPUDevice::createSampler(const SamplerInfo &info) {
|
||||
return ccnew CCWGPUSampler(info);
|
||||
}
|
||||
|
||||
void CCWGPUDevice::present() {
|
||||
auto *queue = static_cast<CCWGPUQueue *>(_queue);
|
||||
_numDrawCalls = queue->getNumDrawCalls();
|
||||
_numInstances = queue->getNumInstances();
|
||||
_numTriangles = queue->getNumTris();
|
||||
queue->resetStatus();
|
||||
|
||||
CCWGPUDescriptorSet::clearCache();
|
||||
|
||||
_currentFrameIndex = (++_currentFrameIndex) % CC_WGPU_MAX_FRAME_COUNT;
|
||||
}
|
||||
|
||||
void CCWGPUDevice::getQueryPoolResults(QueryPool *queryPool) {
|
||||
// _cmdBuff->getQueryPoolResults(queryPool);
|
||||
}
|
||||
|
||||
void CCWGPUDevice::debug() {
|
||||
// auto wgpuCommandEncoder = wgpuDeviceCreateCommandEncoder(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, nullptr);
|
||||
// auto wgpuCommandBuffer = wgpuCommandEncoderFinish(wgpuCommandEncoder, nullptr);
|
||||
// wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &wgpuCommandBuffer);
|
||||
}
|
||||
|
||||
void CCWGPUDevice::initConfigs() {
|
||||
WGPUAdapterProperties props{};
|
||||
wgpuAdapterGetProperties(_gpuDeviceObj->instance.wgpuAdapter, &props);
|
||||
// _deviceName = props.name;
|
||||
// _vendor = props.driverDescription;
|
||||
|
||||
const auto &adapterName = getAdapterTypeName(props.adapterType);
|
||||
const auto &backendName = getBackendTypeName(props.backendType);
|
||||
|
||||
printf("WebGPU:%s enabled with: %s , adapter:%s, backend: %s, vendorID: %u, deviceID:%u\n",
|
||||
_deviceName.c_str(), _vendor.c_str(), adapterName.c_str(), backendName.c_str(), props.vendorID, props.deviceID);
|
||||
|
||||
if (wgpuAdapterHasFeature(_gpuDeviceObj->instance.wgpuAdapter, WGPUFeatureName_TextureCompressionBC)) {
|
||||
_formatFeatures[toNumber(Format::BC1_ALPHA)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC1_SRGB_ALPHA)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC2)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC2_SRGB)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC3)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC3_SRGB)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC4)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC4_SNORM)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC5_SNORM)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC6H_SF16)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC6H_UF16)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC7)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BC7_SRGB)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
}
|
||||
|
||||
if (wgpuAdapterHasFeature(_gpuDeviceObj->instance.wgpuAdapter, WGPUFeatureName_TextureCompressionETC2)) {
|
||||
_formatFeatures[toNumber(Format::ETC2_RGBA8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ETC2_SRGB8_A8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ETC2_RGB8_A1)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ETC2_SRGB8_A1)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ETC2_RGB8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ETC2_SRGB8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::EAC_R11)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::EAC_R11SN)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::EAC_RG11)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::EAC_RG11SN)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
}
|
||||
|
||||
if (wgpuAdapterHasFeature(_gpuDeviceObj->instance.wgpuAdapter, WGPUFeatureName_TextureCompressionASTC)) {
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_4X4)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_4X4)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_5X4)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_5X4)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_5X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_5X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_6X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_6X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_6X6)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_6X6)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_8X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_8X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_8X6)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_8X6)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_8X8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_8X8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_10X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X5)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_10X6)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_10X6)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_10X8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X8)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_10X10)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_10X10)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_12X10)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_SRGBA_12X10)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::ASTC_RGBA_12X12)] = FormatFeature::SAMPLED_TEXTURE;
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUDevice::initLimits() {
|
||||
WGPUSupportedLimits supportLimits;
|
||||
|
||||
// Aug-19th 2022: getlimits not impled.
|
||||
|
||||
#if 0
|
||||
wgpuAdapterGetLimits(_gpuDeviceObj->instance.wgpuAdapter, &supportLimits);
|
||||
|
||||
const auto &limits = supportLimits.limits;
|
||||
_caps.maxVertexAttributes = limits.maxVertexAttributes;
|
||||
_caps.maxVertexUniformVectors = 256;
|
||||
_caps.maxFragmentUniformVectors = 256;
|
||||
_caps.maxTextureUnits = limits.maxSamplersPerShaderStage;
|
||||
_caps.maxImageUnits = limits.maxSampledTexturesPerShaderStage;
|
||||
_caps.maxVertexTextureUnits = limits.maxSampledTexturesPerShaderStage;
|
||||
_caps.maxShaderStorageBufferBindings = limits.maxStorageBuffersPerShaderStage;
|
||||
_caps.maxUniformBlockSize = limits.maxUniformBufferBindingSize;
|
||||
_caps.maxShaderStorageBlockSize = limits.maxStorageBufferBindingSize;
|
||||
_caps.maxShaderStorageBufferBindings = limits.maxStorageBuffersPerShaderStage;
|
||||
_caps.maxTextureSize = limits.maxTextureDimension2D;
|
||||
_caps.uboOffsetAlignment = limits.minUniformBufferOffsetAlignment;
|
||||
|
||||
_caps.maxComputeSharedMemorySize = limits.maxComputeWorkgroupStorageSize;
|
||||
_caps.maxComputeWorkGroupInvocations = limits.maxComputeInvocationsPerWorkgroup;
|
||||
_caps.maxComputeWorkGroupSize = {limits.maxComputeWorkgroupsPerDimension, limits.maxComputeWorkgroupsPerDimension, limits.maxComputeWorkgroupsPerDimension};
|
||||
_caps.maxComputeWorkGroupCount = {limits.maxComputeWorkgroupSizeX, limits.maxComputeWorkgroupSizeY, limits.maxComputeWorkgroupSizeZ};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void CCWGPUDevice::initFeatures() {
|
||||
const FormatFeature completeFeature = FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE | FormatFeature::LINEAR_FILTER | FormatFeature::STORAGE_TEXTURE;
|
||||
|
||||
FormatFeature tempFeature = FormatFeature::RENDER_TARGET | FormatFeature::SAMPLED_TEXTURE | FormatFeature::STORAGE_TEXTURE;
|
||||
|
||||
// render target
|
||||
_formatFeatures[toNumber(Format::R8)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R8UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R8I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG8)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG8UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG8I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA8)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::SRGB8_A8)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA8UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA8I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::BGRA8)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R16UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R16I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R16F)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG16UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG16I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA16UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA16I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R32F)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA32UI)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA32I)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::RGB10A2)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::DEPTH)] |= FormatFeature::RENDER_TARGET;
|
||||
_formatFeatures[toNumber(Format::DEPTH_STENCIL)] |= FormatFeature::RENDER_TARGET;
|
||||
|
||||
// storage
|
||||
_formatFeatures[toNumber(Format::RGBA8)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8SN)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8UI)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8I)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA16UI)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA16I)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32F)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA32UI)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA32I)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGB10A2)] |= FormatFeature::STORAGE_TEXTURE;
|
||||
|
||||
// sampled
|
||||
_formatFeatures[toNumber(Format::R8)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R8SN)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R8UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R8I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG8)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG8SN)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG8UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG8I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::SRGB8_A8)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8SN)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA8I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::BGRA8)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R16UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R16I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R16F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG16UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG16I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA16UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA16I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA32UI)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA32I)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::RGB10A2)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::R11G11B10F)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::DEPTH)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
_formatFeatures[toNumber(Format::DEPTH_STENCIL)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
|
||||
_formatFeatures[toNumber(Format::RGB9E5)] |= FormatFeature::SAMPLED_TEXTURE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R8)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG8)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB8)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA8)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R8SN)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG8SN)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB8SN)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA8SN)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R8I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG8I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB8I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA8I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R8UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG8UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB8UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA8UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R16I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG16I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB16I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA16I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R16UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG16UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB16UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA16UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R16F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG16F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB16F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA16F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R32UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG32UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB32UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA32UI)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R32I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG32I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB32I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA32I)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
_formatFeatures[toNumber(Format::R32F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RG32F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGB32F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
_formatFeatures[toNumber(Format::RGBA32F)] |= FormatFeature::VERTEX_ATTRIBUTE;
|
||||
|
||||
//
|
||||
_features[toNumber(Feature::ELEMENT_INDEX_UINT)] = true;
|
||||
_features[toNumber(Feature::INSTANCED_ARRAYS)] = true;
|
||||
_features[toNumber(Feature::MULTIPLE_RENDER_TARGETS)] = true;
|
||||
_features[toNumber(Feature::BLEND_MINMAX)] = true;
|
||||
_features[toNumber(Feature::COMPUTE_SHADER)] = true;
|
||||
_features[toNumber(Feature::INPUT_ATTACHMENT_BENEFIT)] = true;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
} // namespace cc
|
||||
177
cocos/renderer/gfx-wgpu/WGPUDevice.h
Normal file
177
cocos/renderer/gfx-wgpu/WGPUDevice.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "WGPUObject.h"
|
||||
#include "base/std/container/vector.h"
|
||||
#include "gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUDeviceObject;
|
||||
|
||||
class CCWGPUSwapchain;
|
||||
class CCWGPUTexture;
|
||||
class WGPUGeneralBarrier;
|
||||
|
||||
class CCWGPUDevice final : public Device {
|
||||
public:
|
||||
static CCWGPUDevice *getInstance();
|
||||
|
||||
CCWGPUDevice();
|
||||
~CCWGPUDevice();
|
||||
|
||||
void acquire(const std::vector<Swapchain *> &swapchains) {
|
||||
return acquire(swapchains.data(), swapchains.size());
|
||||
}
|
||||
void acquire(Swapchain *const *swapchains, uint32_t count) override;
|
||||
void present() override;
|
||||
|
||||
inline CCWGPUDeviceObject *gpuDeviceObject() { return _gpuDeviceObj; }
|
||||
inline uint8_t getCurrentFrameIndex() const { return _currentFrameIndex; }
|
||||
inline CCWGPURecycleBin *recycleBin() { return &_recycleBin[_currentFrameIndex]; }
|
||||
inline void registerSwapchain(CCWGPUSwapchain *swapchain) { _swapchains.push_back(swapchain); }
|
||||
inline void unRegisterSwapchain(CCWGPUSwapchain *swapchain) {
|
||||
auto iter = std::find(_swapchains.begin(), _swapchains.end(), swapchain);
|
||||
if (iter != _swapchains.end()) {
|
||||
_swapchains.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void moveToTrash(T t);
|
||||
|
||||
// CCWGPUStagingBuffer *stagingBuffer() {
|
||||
// return _stagingBuffers[_currentFrameIndex];
|
||||
// }
|
||||
|
||||
void debug();
|
||||
|
||||
using Device::createBuffer;
|
||||
using Device::createDescriptorSet;
|
||||
using Device::createDescriptorSetLayout;
|
||||
using Device::createFramebuffer;
|
||||
using Device::createInputAssembler;
|
||||
using Device::createPipelineLayout;
|
||||
using Device::createPipelineState;
|
||||
using Device::createRenderPass;
|
||||
using Device::createShader;
|
||||
using Device::createSwapchain;
|
||||
using Device::createTexture;
|
||||
using Device::getGeneralBarrier;
|
||||
using Device::getSampler;
|
||||
using Device::initialize;
|
||||
|
||||
void frameSync() override {};
|
||||
|
||||
Shader *createShader(const ShaderInfo &, const std::vector<std::vector<uint32_t>> &);
|
||||
|
||||
void copyBuffersToTexture(const std::vector<std::vector<uint8_t>> &buffers, Texture *dst, const std::vector<BufferTextureCopy> ®ions) {
|
||||
std::vector<const uint8_t *> datas(buffers.size());
|
||||
for (size_t i = 0; i < buffers.size(); ++i) {
|
||||
datas[i] = buffers[i].data();
|
||||
}
|
||||
return copyBuffersToTexture(datas.data(), dst, regions.data(), regions.size());
|
||||
}
|
||||
uint32_t getGFXAPI() const {
|
||||
return static_cast<uint32_t>(Device::getGfxAPI());
|
||||
};
|
||||
uint32_t hasFeature(uint32_t feature) {
|
||||
return static_cast<uint32_t>(Device::hasFeature(Feature{feature}));
|
||||
};
|
||||
inline MemoryStatus getMemStatus() const {
|
||||
return _memoryStatus;
|
||||
}
|
||||
uint32_t getFormatFeatures(uint32_t format) {
|
||||
return static_cast<uint32_t>(Device::getFormatFeatures(Format{format}));
|
||||
};
|
||||
|
||||
// ems export override
|
||||
EXPORT_EMS(
|
||||
void copyTextureToBuffers(Texture *src, const emscripten::val &buffers, const emscripten::val ®ions);
|
||||
emscripten::val copyTextureToBuffers(Texture * src, const BufferTextureCopyList ®ions);
|
||||
void copyBuffersToTexture(const emscripten::val &v, Texture *dst, const std::vector<BufferTextureCopy> ®ions);)
|
||||
|
||||
void initFeatures();
|
||||
void initLimits();
|
||||
void initConfigs();
|
||||
|
||||
protected:
|
||||
static CCWGPUDevice *instance;
|
||||
|
||||
bool doInit(const DeviceInfo &info) override;
|
||||
void doDestroy() override;
|
||||
CommandBuffer *createCommandBuffer(const CommandBufferInfo &info, bool hasAgent) override;
|
||||
Queue *createQueue() 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;
|
||||
Swapchain *createSwapchain() override;
|
||||
QueryPool *createQueryPool() override;
|
||||
Sampler *createSampler(const SamplerInfo &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;
|
||||
|
||||
uint8_t _currentFrameIndex{0};
|
||||
CCWGPUDeviceObject *_gpuDeviceObj = nullptr;
|
||||
ccstd::vector<CCWGPUSwapchain *> _swapchains;
|
||||
|
||||
CCWGPURecycleBin _recycleBin[CC_WGPU_MAX_FRAME_COUNT];
|
||||
};
|
||||
|
||||
template <>
|
||||
inline void CCWGPUDevice::moveToTrash<WGPUBuffer>(WGPUBuffer t) {
|
||||
_recycleBin[_currentFrameIndex].bufferBin.collect(t);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void CCWGPUDevice::moveToTrash<WGPUTexture>(WGPUTexture t) {
|
||||
_recycleBin[_currentFrameIndex].textureBin.collect(t);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void CCWGPUDevice::moveToTrash<WGPUQuerySet>(WGPUQuerySet t) {
|
||||
_recycleBin[_currentFrameIndex].queryBin.collect(t);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
} // namespace cc
|
||||
175
cocos/renderer/gfx-wgpu/WGPUEMSImpl.cpp
Normal file
175
cocos/renderer/gfx-wgpu/WGPUEMSImpl.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://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 <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/variadic/to_seq.hpp>
|
||||
#include <vector>
|
||||
#include "WGPUBuffer.h"
|
||||
#include "WGPUCommandBuffer.h"
|
||||
#include "WGPUDef.h"
|
||||
#include "WGPUDescriptorSet.h"
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUFrameBuffer.h"
|
||||
#include "WGPUInputAssembler.h"
|
||||
#include "WGPUQueue.h"
|
||||
#include "WGPURenderPass.h"
|
||||
#include "WGPUSampler.h"
|
||||
#include "WGPUShader.h"
|
||||
#include "WGPUSwapchain.h"
|
||||
#include "WGPUTexture.h"
|
||||
#include "gfx-base/GFXDef-common.h"
|
||||
#include "states/WGPUBufferBarrier.h"
|
||||
#include "states/WGPUGeneralBarrier.h"
|
||||
#include "states/WGPUTextureBarrier.h"
|
||||
namespace cc::gfx {
|
||||
|
||||
using ::emscripten::allow_raw_pointers;
|
||||
// using ::emscripten::convertJSArrayToNumberVector_local;
|
||||
using ::emscripten::val;
|
||||
|
||||
#define CACHE_NAME(r, _, property) \
|
||||
const val BOOST_PP_CAT(property, _val){BOOST_PP_STRINGIZE(property)};
|
||||
|
||||
#define CACHE_EMS_VAL(...) \
|
||||
BOOST_PP_SEQ_FOR_EACH(CACHE_NAME, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__));
|
||||
|
||||
CACHE_EMS_VAL(length)
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> convertJSArrayToNumberVector_local(const val& v) {
|
||||
const size_t l = v[length_val].as<size_t>();
|
||||
|
||||
std::vector<T> rv;
|
||||
rv.resize(l);
|
||||
|
||||
// Copy the array into our vector through the use of typed arrays.
|
||||
// It will try to convert each element through Number().
|
||||
// See https://www.ecma-international.org/ecma-262/6.0/#sec-%typedarray%.prototype.set-array-offset
|
||||
// and https://www.ecma-international.org/ecma-262/6.0/#sec-tonumber
|
||||
val memoryView{emscripten::typed_memory_view(l, rv.data())};
|
||||
memoryView.call<void>("set", v);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> vecFromJSArray_local(const val& v) {
|
||||
const size_t l = v[length_val].as<size_t>();
|
||||
|
||||
std::vector<T> rv;
|
||||
rv.reserve(l);
|
||||
for (size_t i = 0; i < l; ++i) {
|
||||
rv.push_back(v[i].as<T>());
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define UNREACHABLE_CONDITION CC_ABORT();
|
||||
|
||||
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int))
|
||||
|
||||
#define ASSIGN_PROERTY_BY_SEQ(r, obj, property) \
|
||||
if (!ems_##obj[BOOST_PP_CAT(property, _val)].isUndefined() && !ems_##obj[BOOST_PP_CAT(property, _val)].isNull()) { \
|
||||
obj.property = decltype(obj.property){ems_##obj[BOOST_PP_CAT(property, _val)].as<GetType<decltype(obj.property)>::type>(allow_raw_pointers())}; \
|
||||
}
|
||||
|
||||
#define ASSIGN_FROM_EMS(obj, ...) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH(ASSIGN_PROERTY_BY_SEQ, obj, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
#define SET_PROERTY_BY_SEQ(r, obj, property) \
|
||||
ems_##obj.set(BOOST_STRINGIZE(property), static_cast<GetType<decltype(obj.property)>::type>(obj.property));
|
||||
|
||||
#define SET_TO_EMS(obj, ...) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH(SET_PROERTY_BY_SEQ, obj, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
#define ASSIGN_VEC_BY_SEQ(r, obj, property) \
|
||||
obj.property = std::move(convertJSArrayToNumberVector_local<decltype(obj.property)::value_type>(ems_##obj[#property]));
|
||||
|
||||
#define ASSIGN_FROM_EMSARRAY(obj, ...) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH(ASSIGN_VEC_BY_SEQ, obj, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
#ifdef CC_DEBUG
|
||||
#define CHECK_VOID(v) \
|
||||
if (v.isUndefined() || v.isNull()) { \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_PTR(v) \
|
||||
if (v.isUndefined() || v.isNull()) { \
|
||||
return nullptr; \
|
||||
}
|
||||
#else
|
||||
#define CHECK_VOID(v)
|
||||
#define CHECK_PTR(v)
|
||||
#endif
|
||||
|
||||
#define EMSArraysToU8Vec(v, i) (convertJSArrayToNumberVector_local<uint8_t>(v[i]))
|
||||
|
||||
void CCWGPUCommandBuffer::updateBuffer(Buffer* buff, const emscripten::val& v, uint32_t size) {
|
||||
ccstd::vector<uint8_t> buffer = convertJSArrayToNumberVector_local<uint8_t>(v);
|
||||
updateBuffer(buff, reinterpret_cast<const void*>(buffer.data()), size);
|
||||
}
|
||||
|
||||
void CCWGPUBuffer::update(const val& v, uint32_t size) {
|
||||
// this is the most fastest way from js array to vector now
|
||||
ccstd::vector<uint8_t> buffer = convertJSArrayToNumberVector_local<uint8_t>(v);
|
||||
update(reinterpret_cast<const void*>(buffer.data()), size);
|
||||
}
|
||||
|
||||
void CCWGPUDevice::copyTextureToBuffers(Texture* src, const emscripten::val& buffers, const emscripten::val& regions) {
|
||||
// @hana-alice
|
||||
}
|
||||
|
||||
void CCWGPUDevice::copyBuffersToTexture(const emscripten::val& v, Texture* dst, const std::vector<BufferTextureCopy>& regions) {
|
||||
CHECK_VOID(v);
|
||||
auto len = v[length_val].as<unsigned>();
|
||||
len = v[length_val].as<unsigned>();
|
||||
std::vector<std::vector<uint8_t>> lifeProlonger(len);
|
||||
std::vector<const uint8_t*> buffers;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
lifeProlonger[i] = EMSArraysToU8Vec(v, i);
|
||||
buffers.push_back(lifeProlonger[i].data());
|
||||
}
|
||||
|
||||
return copyBuffersToTexture(buffers.data(), dst, regions.data(), regions.size());
|
||||
}
|
||||
|
||||
void CCWGPUShader::reflectBinding(const emscripten::val &vals) {
|
||||
const std::vector<uint8_t>& bindings = convertJSArrayToNumberVector<uint8_t>(vals);
|
||||
_gpuShaderObject->bindings.emplace_back(bindings);
|
||||
}
|
||||
|
||||
} // namespace cc::gfx
|
||||
440
cocos/renderer/gfx-wgpu/WGPUExports.h
Normal file
440
cocos/renderer/gfx-wgpu/WGPUExports.h
Normal file
@@ -0,0 +1,440 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://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 "WGPUBuffer.h"
|
||||
#include "WGPUCommandBuffer.h"
|
||||
#include "WGPUDef.h"
|
||||
#include "WGPUDescriptorSet.h"
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUFrameBuffer.h"
|
||||
#include "WGPUInputAssembler.h"
|
||||
#include "WGPUPipelineLayout.h"
|
||||
#include "WGPUPipelineState.h"
|
||||
#include "WGPUQueue.h"
|
||||
#include "WGPURenderPass.h"
|
||||
#include "WGPUSampler.h"
|
||||
#include "WGPUShader.h"
|
||||
#include "WGPUSwapchain.h"
|
||||
#include "WGPUTexture.h"
|
||||
#include "boost/pfr.hpp"
|
||||
#include "boost/type_index.hpp"
|
||||
#include "states/WGPUBufferBarrier.h"
|
||||
#include "states/WGPUGeneralBarrier.h"
|
||||
#include "states/WGPUTextureBarrier.h"
|
||||
|
||||
REGISTER_GFX_PTRS_FOR_STRUCT(Device, Buffer, Texture, GeneralBarrier, Queue, RenderPass, Shader, PipelineLayout, DescriptorSetLayout, CommandBuffer, DescriptorSet, Sampler, CCWGPUGPUDescriptorSetObject);
|
||||
|
||||
namespace cc::gfx {
|
||||
|
||||
using ::emscripten::allow_raw_pointer;
|
||||
using ::emscripten::allow_raw_pointers;
|
||||
using ::emscripten::arg;
|
||||
using ::emscripten::base;
|
||||
using ::emscripten::class_;
|
||||
using ::emscripten::constant;
|
||||
using ::emscripten::enum_;
|
||||
using ::emscripten::function;
|
||||
using ::emscripten::pure_virtual;
|
||||
using ::emscripten::register_vector;
|
||||
using ::emscripten::select_overload;
|
||||
using ::emscripten::val;
|
||||
using ::emscripten::value_object;
|
||||
|
||||
using String = ccstd::string;
|
||||
using ccstd::vector;
|
||||
|
||||
EMSCRIPTEN_BINDINGS(WEBGPU_DEVICE_WASM_EXPORT) {
|
||||
// register_vector<uint32_t>("Uint32Vector");
|
||||
|
||||
EXPORT_STRUCT_POD(Size, x, y, z);
|
||||
EXPORT_STRUCT_POD(DeviceCaps, maxVertexAttributes, maxVertexUniformVectors, maxFragmentUniformVectors, maxTextureUnits, maxImageUnits, maxVertexTextureUnits, maxColorRenderTargets,
|
||||
maxShaderStorageBufferBindings, maxShaderStorageBlockSize, maxUniformBufferBindings, maxUniformBlockSize, maxTextureSize, maxCubeMapTextureSize, uboOffsetAlignment,
|
||||
maxComputeSharedMemorySize, maxComputeWorkGroupInvocations, maxComputeWorkGroupSize, maxComputeWorkGroupCount, supportQuery, clipSpaceMinZ, screenSpaceSignY, clipSpaceSignY);
|
||||
EXPORT_STRUCT_POD(Offset, x, y, z);
|
||||
EXPORT_STRUCT_POD(Rect, x, y, width, height);
|
||||
EXPORT_STRUCT_POD(Extent, width, height, depth);
|
||||
EXPORT_STRUCT_POD(TextureSubresLayers, mipLevel, baseArrayLayer, layerCount);
|
||||
EXPORT_STRUCT_POD(TextureCopy, srcSubres, srcOffset, dstSubres, dstOffset, extent);
|
||||
EXPORT_STRUCT_POD(TextureBlit, srcSubres, srcOffset, srcExtent, dstSubres, dstOffset, dstExtent);
|
||||
EXPORT_STRUCT_POD(BufferTextureCopy, buffOffset, buffStride, buffTexHeight, texOffset, texExtent, texSubres);
|
||||
EXPORT_STRUCT_POD(Viewport, left, top, width, height, minDepth, maxDepth);
|
||||
EXPORT_STRUCT_POD(Color, x, y, z, w);
|
||||
EXPORT_STRUCT_POD(BindingMappingInfo, maxBlockCounts, maxSamplerTextureCounts, maxSamplerCounts, maxTextureCounts, maxBufferCounts, maxImageCounts, maxSubpassInputCounts, setIndices);
|
||||
// SwapchainInfo ignore windowHandle
|
||||
EXPORT_STRUCT_NPOD(SwapchainInfo, vsyncMode, width, height);
|
||||
EXPORT_STRUCT_POD(DeviceInfo, bindingMappingInfo);
|
||||
EXPORT_STRUCT_POD(BufferInfo, usage, memUsage, size, stride, flags);
|
||||
EXPORT_STRUCT_NPOD(BufferViewInfo, buffer, offset, range);
|
||||
EXPORT_STRUCT_POD(DrawInfo, vertexCount, firstVertex, indexCount, firstIndex, vertexOffset, instanceCount, firstInstance);
|
||||
EXPORT_STRUCT_NPOD(DispatchInfo, groupCountX, groupCountY, groupCountZ, indirectBuffer, indirectOffset);
|
||||
EXPORT_STRUCT_POD(IndirectBuffer, drawInfos);
|
||||
EXPORT_STRUCT_NPOD(TextureInfo, type, usage, format, width, height, flags, layerCount, levelCount, samples, depth, externalRes);
|
||||
EXPORT_STRUCT_NPOD(TextureViewInfo, texture, type, format, baseLevel, levelCount, baseLayer, layerCount);
|
||||
EXPORT_STRUCT_POD(SamplerInfo, minFilter, magFilter, mipFilter, addressU, addressV, addressW, maxAnisotropy, cmpFunc);
|
||||
EXPORT_STRUCT_POD(Uniform, name, type, count);
|
||||
EXPORT_STRUCT_POD(UniformBlock, set, binding, name, members, count);
|
||||
EXPORT_STRUCT_POD(UniformSamplerTexture, set, binding, name, type, count);
|
||||
EXPORT_STRUCT_POD(UniformSampler, set, binding, name, count);
|
||||
EXPORT_STRUCT_POD(UniformTexture, set, binding, name, type, count);
|
||||
EXPORT_STRUCT_POD(UniformStorageImage, set, binding, name, type, count, memoryAccess);
|
||||
EXPORT_STRUCT_POD(UniformStorageBuffer, set, binding, name, count, memoryAccess);
|
||||
EXPORT_STRUCT_POD(UniformInputAttachment, set, binding, name, count);
|
||||
EXPORT_STRUCT_POD(ShaderStage, stage, source);
|
||||
EXPORT_STRUCT_POD(Attribute, name, format, isNormalized, stream, isInstanced, location);
|
||||
EXPORT_STRUCT_POD(ShaderInfo, name, stages, attributes, blocks, buffers, samplerTextures, samplers, textures, images, subpassInputs);
|
||||
EXPORT_STRUCT_NPOD(InputAssemblerInfo, attributes, vertexBuffers, indexBuffer, indirectBuffer);
|
||||
EXPORT_STRUCT_NPOD(ColorAttachment, format, sampleCount, loadOp, storeOp, barrier);
|
||||
EXPORT_STRUCT_NPOD(DepthStencilAttachment, format, sampleCount, depthLoadOp, depthStoreOp, stencilLoadOp, stencilStoreOp, barrier);
|
||||
EXPORT_STRUCT_POD(SubpassInfo, inputs, colors, resolves, preserves, depthStencil, depthStencilResolve, depthResolveMode, stencilResolveMode);
|
||||
|
||||
// MAYBE TODO(Zeqiang): all ts related backend no need to care about barriers.
|
||||
EXPORT_STRUCT_POD(SubpassDependency, srcSubpass, dstSubpass, prevAccesses, nextAccesses);
|
||||
EXPORT_STRUCT_POD(RenderPassInfo, colorAttachments, depthStencilAttachment, subpasses, dependencies);
|
||||
EXPORT_STRUCT_POD(GeneralBarrierInfo, prevAccesses, nextAccesses, type);
|
||||
EXPORT_STRUCT_POD(ResourceRange, width, height, depthOrArraySize, firstSlice, numSlices, mipLevel, levelCount, basePlane, planeCount);
|
||||
EXPORT_STRUCT_NPOD(TextureBarrierInfo, prevAccesses, nextAccesses, type, range, discardContents, srcQueue, dstQueue);
|
||||
EXPORT_STRUCT_NPOD(BufferBarrierInfo, prevAccesses, nextAccesses, type, offset, size, discardContents, srcQueue, dstQueue);
|
||||
EXPORT_STRUCT_NPOD(FramebufferInfo, renderPass, colorTextures, depthStencilTexture);
|
||||
EXPORT_STRUCT_NPOD(WGPUGPUDescriptor, type, buffer, texture, sampler);
|
||||
EXPORT_STRUCT_NPOD(CCWGPUGPUDescriptorSetObject, gpuDescriptors, descriptorIndices);
|
||||
EXPORT_STRUCT_NPOD(DescriptorSetLayoutBinding, binding, descriptorType, count, stageFlags, immutableSamplers);
|
||||
EXPORT_STRUCT_POD(DescriptorSetLayoutInfo, bindings);
|
||||
EXPORT_STRUCT_NPOD(DescriptorSetInfo, layout);
|
||||
EXPORT_STRUCT_NPOD(PipelineLayoutInfo, setLayouts);
|
||||
EXPORT_STRUCT_POD(InputState, attributes);
|
||||
EXPORT_STRUCT_POD(RasterizerState, isDiscard, polygonMode, shadeModel, cullMode, isFrontFaceCCW, depthBiasEnabled, depthBias, depthBiasClamp, depthBiasSlop, isDepthClip, isMultisample, lineWidth);
|
||||
EXPORT_STRUCT_POD(DepthStencilState, depthTest, depthWrite, depthFunc, stencilTestFront, stencilFuncFront, stencilReadMaskFront, stencilWriteMaskFront, stencilFailOpFront, stencilZFailOpFront, stencilPassOpFront,
|
||||
stencilRefFront, stencilTestBack, stencilFuncBack, stencilReadMaskBack, stencilWriteMaskBack, stencilFailOpBack, stencilZFailOpBack, stencilPassOpBack, stencilRefBack);
|
||||
EXPORT_STRUCT_POD(BlendTarget, blend, blendSrc, blendDst, blendEq, blendSrcAlpha, blendDstAlpha, blendAlphaEq, blendColorMask);
|
||||
EXPORT_STRUCT_POD(BlendState, isA2C, isIndepend, blendColor, targets)
|
||||
// MAYBE TODO(Zeqiang): no subpass in TS now
|
||||
EXPORT_STRUCT_NPOD(PipelineStateInfo, shader, pipelineLayout, renderPass, inputState, rasterizerState, depthStencilState, blendState, primitive, dynamicStates, bindPoint);
|
||||
EXPORT_STRUCT_NPOD(CommandBufferInfo, queue);
|
||||
EXPORT_STRUCT_POD(QueueInfo, type);
|
||||
EXPORT_STRUCT_POD(QueryPoolInfo, type, maxQueryObjects, forceWait);
|
||||
// EXPORT_STRUCT_POD(FormatInfo, name, size, count, type, hasAlpha, hasDepth, hasStencil, isCompressed);
|
||||
EXPORT_STRUCT_POD(MemoryStatus, bufferSize, textureSize);
|
||||
EXPORT_STRUCT_POD(DynamicStencilStates, writeMask, compareMask, reference);
|
||||
EXPORT_STRUCT_POD(DynamicStates, viewport, scissor, blendConstant, lineWidth, depthBiasConstant, depthBiasClamp, depthBiasSlope, depthMinBounds, depthMaxBounds, stencilStatesFront, stencilStatesBack);
|
||||
//--------------------------------------------------CLASS---------------------------------------------------------------------------
|
||||
class_<Swapchain>("Swapchain")
|
||||
.function("initialize", &Swapchain::initialize, allow_raw_pointer<arg<0>>())
|
||||
.function("destroy", &Swapchain::destroy)
|
||||
.function("resize", select_overload<void(uint32_t, uint32_t, SurfaceTransform)>(&Swapchain::resize))
|
||||
.function("destroySurface", &Swapchain::destroySurface)
|
||||
.function("createSurface", &Swapchain::createSurface, allow_raw_pointer<arg<0>>())
|
||||
.property("width", &Swapchain::getWidth)
|
||||
.property("height", &Swapchain::getHeight)
|
||||
.property("surfaceTransform", &Swapchain::getSurfaceTransform)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Swapchain::getObjectID));
|
||||
class_<CCWGPUSwapchain, base<Swapchain>>("CCWGPUSwapchain")
|
||||
.property("depthStencilTexture", &CCWGPUSwapchain::getDepthStencilTexture, &CCWGPUSwapchain::setDepthStencilTexture)
|
||||
.property("colorTexture", &CCWGPUSwapchain::getColorTexture, &CCWGPUSwapchain::setColorTexture);
|
||||
|
||||
class_<Device>("Device")
|
||||
.function("initialize", &Device::initialize)
|
||||
.function("destroy", &Device::destroy, pure_virtual())
|
||||
.function("present", &Device::present, pure_virtual())
|
||||
.function("createQueue", select_overload<Queue *(const QueueInfo &)>(&Device::createQueue), allow_raw_pointer<arg<0>>())
|
||||
.function("createSwapchain", select_overload<Swapchain *(const SwapchainInfo &)>(&Device::createSwapchain), allow_raw_pointer<arg<0>>())
|
||||
.function("createRenderPass", select_overload<RenderPass *(const RenderPassInfo &)>(&Device::createRenderPass))
|
||||
.function("createFramebuffer", select_overload<Framebuffer *(const FramebufferInfo &)>(&Device::createFramebuffer), allow_raw_pointer<arg<0>>())
|
||||
.function("createBuffer", select_overload<Buffer *(const BufferInfo &)>(&Device::createBuffer), allow_raw_pointer<arg<0>>())
|
||||
.function("createBufferView", select_overload<Buffer *(const BufferViewInfo &)>(&Device::createBuffer), allow_raw_pointer<arg<0>>())
|
||||
.function("createTexture", select_overload<Texture *(const TextureInfo &)>(&Device::createTexture), allow_raw_pointer<arg<0>>())
|
||||
.function("createTextureView", select_overload<Texture *(const TextureViewInfo &)>(&Device::createTexture), allow_raw_pointer<arg<0>>())
|
||||
.function("createDescriptorSetLayout", select_overload<DescriptorSetLayout *(const DescriptorSetLayoutInfo &)>(&Device::createDescriptorSetLayout), allow_raw_pointer<arg<0>>())
|
||||
.function("createInputAssembler", select_overload<InputAssembler *(const InputAssemblerInfo &)>(&Device::createInputAssembler), allow_raw_pointer<arg<0>>())
|
||||
.function("createPipelineState", select_overload<PipelineState *(const PipelineStateInfo &)>(&Device::createPipelineState), allow_raw_pointer<arg<0>>())
|
||||
.function("createDescriptorSet", select_overload<DescriptorSet *(const DescriptorSetInfo &)>(&Device::createDescriptorSet), allow_raw_pointer<arg<0>>())
|
||||
.function("createPipelineLayout", select_overload<PipelineLayout *(const PipelineLayoutInfo &)>(&Device::createPipelineLayout), allow_raw_pointer<arg<0>>())
|
||||
.function("getSampler", &Device::getSampler, allow_raw_pointer<arg<0>>())
|
||||
.function("getGeneralBarrier", &Device::getGeneralBarrier, allow_raw_pointer<arg<0>>())
|
||||
// .function("createTextureBarrier", select_overload<TextureBarrier*(const TextureBarrierInfo&)>(&Device::createTextureBarrier),
|
||||
// /* pure_virtual(), */ allow_raw_pointer<arg<0>>())
|
||||
// .function("flushCommands", &Device::flushCommands, allow_raw_pointers())
|
||||
.function("present", select_overload<void(void)>(&Device::present))
|
||||
.function("enableAutoBarrier", &Device::enableAutoBarrier)
|
||||
.property("queue", &Device::getQueue)
|
||||
.property("commandBuffer", &Device::getCommandBuffer)
|
||||
.property("capabilities", &Device::getCapabilities)
|
||||
.property("name", &Device::getDeviceName)
|
||||
.property("renderer", &Device::getRenderer)
|
||||
.property("vendor", &Device::getVendor)
|
||||
.property("numDrawCalls", &Device::getNumDrawCalls)
|
||||
.property("numInstances", &Device::getNumInstances)
|
||||
.property("numTris", &Device::getNumTris);
|
||||
class_<CCWGPUDevice, base<Device>>("CCWGPUDevice")
|
||||
// .class_function("getInstance", &CCWGPUDevice::getInstance, allow_raw_pointer<arg<0>>())
|
||||
.constructor<>()
|
||||
.function("debug", &CCWGPUDevice::debug)
|
||||
|
||||
.function("acquire", select_overload<void(const std::vector<Swapchain *> &)>(&CCWGPUDevice::acquire),
|
||||
/* pure_virtual(), */ allow_raw_pointer<arg<0>>())
|
||||
.function("createShaderNative", select_overload<Shader *(const ShaderInfo &)>(&CCWGPUDevice::createShader))
|
||||
.function("copyTextureToBuffers", select_overload<void(Texture * src, const emscripten::val &, const emscripten::val &)>(&CCWGPUDevice::copyTextureToBuffers),
|
||||
/* pure_virtual(), */ allow_raw_pointers())
|
||||
.function("copyBuffersToTexture", select_overload<void(const emscripten::val &, Texture *dst, const std::vector<BufferTextureCopy> &)>(&CCWGPUDevice::copyBuffersToTexture),
|
||||
/* pure_virtual(), */ allow_raw_pointers())
|
||||
.function("getFormatFeatures", select_overload<uint32_t(uint32_t)>(&CCWGPUDevice::getFormatFeatures))
|
||||
.function("hasFeature", &CCWGPUDevice::hasFeature)
|
||||
.property("gfxAPI", &CCWGPUDevice::getGFXAPI)
|
||||
.property("memoryStatus", &CCWGPUDevice::getMemStatus);
|
||||
|
||||
class_<RenderPass>("RenderPass")
|
||||
.class_function("computeHash", select_overload<ccstd::hash_t(const RenderPassInfo &)>(&RenderPass::computeHash), allow_raw_pointer<arg<0>>())
|
||||
.function("destroy", &RenderPass::destroy)
|
||||
.function("initialize", select_overload<void(const RenderPassInfo &)>(&CCWGPURenderPass::initialize), allow_raw_pointer<arg<0>>())
|
||||
.property("colorAttachments", &RenderPass::getColorAttachments)
|
||||
.property("depthStencilAttachment", &RenderPass::getDepthStencilAttachment)
|
||||
.property("subpasses", &RenderPass::getSubpasses)
|
||||
.property("dependencies", &RenderPass::getDependencies)
|
||||
.property("hash", &RenderPass::getHash)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&RenderPass::getObjectID));
|
||||
class_<CCWGPURenderPass, base<RenderPass>>("CCWGPURenderPass")
|
||||
.constructor<>();
|
||||
|
||||
class_<Texture>("Texture")
|
||||
.class_function("computeHash", select_overload<ccstd::hash_t(const TextureInfo &)>(&Texture::computeHash), allow_raw_pointer<arg<0>>())
|
||||
.function("initialize", select_overload<void(const TextureInfo &)>(&Texture::initialize), allow_raw_pointer<arg<0>>())
|
||||
.function("initializeView", select_overload<void(const TextureViewInfo &)>(&Texture::initialize), allow_raw_pointer<arg<0>>())
|
||||
.function("destroy", &Texture::destroy)
|
||||
.function("resize", &Texture::resize)
|
||||
.property("info", &Texture::getInfo)
|
||||
.property("viewInfo", &Texture::getViewInfo)
|
||||
.property("width", &Texture::getWidth)
|
||||
.property("height", &Texture::getHeight)
|
||||
.property("size", &Texture::getSize)
|
||||
.property("isTextureView", &Texture::isTextureView)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Texture::getObjectID));
|
||||
class_<CCWGPUTexture, base<Texture>>("CCWGPUTexture")
|
||||
.property("depth", &CCWGPUTexture::getDepth)
|
||||
.property("layerCount", &CCWGPUTexture::getLayerCount)
|
||||
.property("levelCount", &CCWGPUTexture::getLevelCount)
|
||||
.property("type", &CCWGPUTexture::getTextureType)
|
||||
.property("usage", &CCWGPUTexture::getTextureUsage)
|
||||
.property("format", &CCWGPUTexture::getTextureFormat)
|
||||
.property("samples", &CCWGPUTexture::getTextureSamples)
|
||||
.property("flags", &CCWGPUTexture::getTextureFlags)
|
||||
.constructor<>();
|
||||
|
||||
class_<Framebuffer>("Framebuffer")
|
||||
.class_function("computeHash", select_overload<ccstd::hash_t(const FramebufferInfo &)>(&Framebuffer::computeHash), allow_raw_pointer<arg<0>>())
|
||||
.function("destroy", &Framebuffer::destroy)
|
||||
.function("initialize", &Framebuffer::initialize, allow_raw_pointer<arg<0>>())
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Framebuffer::getObjectID));
|
||||
class_<CCWGPUFramebuffer, base<Framebuffer>>("CCWGPUFramebuffer")
|
||||
.constructor<>()
|
||||
.property("renderPass", &CCWGPUFramebuffer::getRenderPass, &CCWGPUFramebuffer::setRenderPass)
|
||||
.property("colorTextures", &CCWGPUFramebuffer::getColorTextures, &CCWGPUFramebuffer::setColorTextures)
|
||||
.property("depthStencilTexture", &CCWGPUFramebuffer::getDepthStencilTexture, &CCWGPUFramebuffer::setDepthStencilTexture);
|
||||
|
||||
class_<Sampler>("Sampler")
|
||||
.function("getInfo", &Sampler::getInfo)
|
||||
.property("hash", &Sampler::getHash)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Sampler::getObjectID));
|
||||
class_<CCWGPUSampler, base<Sampler>>("CCWGPUSampler")
|
||||
.constructor<const SamplerInfo &>();
|
||||
|
||||
class_<Buffer>("Buffer")
|
||||
.function("resize", &Buffer::resize)
|
||||
.function("destroy", &Buffer::destroy)
|
||||
.property("size", &Buffer::getSize)
|
||||
.property("stride", &Buffer::getStride)
|
||||
.property("count", &Buffer::getCount)
|
||||
.property("usage", &Buffer::getUsage)
|
||||
.property("memUsage", &Buffer::getMemUsage)
|
||||
.property("flags", &Buffer::getFlags)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Buffer::getObjectID));
|
||||
class_<CCWGPUBuffer, base<Buffer>>("CCWGPUBuffer")
|
||||
// .function("update", select_overload<void(const DrawInfoList &infos)>(&CCWGPUBuffer::update), allow_raw_pointer<arg<0>>())
|
||||
.function("updateIndirect", select_overload<void(const DrawInfoList &)>(&CCWGPUBuffer::update))
|
||||
.function("update", select_overload<void(const emscripten::val &v, uint32_t)>(&CCWGPUBuffer::update))
|
||||
.constructor<>();
|
||||
|
||||
class_<DescriptorSetLayout>("DescriptorSetLayout")
|
||||
.function("initialize", &DescriptorSetLayout::initialize)
|
||||
.function("destroy", &DescriptorSetLayout::destroy)
|
||||
.property("bindings", &DescriptorSetLayout::getBindings)
|
||||
.property("bindingIndices", &DescriptorSetLayout::getBindingIndices)
|
||||
.property("descriptorIndices", &DescriptorSetLayout::getDescriptorIndices)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&DescriptorSetLayout::getObjectID));
|
||||
class_<CCWGPUDescriptorSetLayout, base<DescriptorSetLayout>>("CCWGPUDescriptorSetLayout")
|
||||
.constructor<>();
|
||||
|
||||
class_<DescriptorSet>("DescriptorSet")
|
||||
.function("initialize", &DescriptorSet::initialize)
|
||||
.function("destroy", &DescriptorSet::destroy)
|
||||
.function("update", &DescriptorSet::update)
|
||||
.function("bindBuffer", select_overload<void(uint32_t, Buffer *)>(&DescriptorSet::bindBuffer), allow_raw_pointer<arg<1>>())
|
||||
.function("bindBuffer", select_overload<void(uint32_t, Buffer *, uint32_t)>(&DescriptorSet::bindBuffer), allow_raw_pointer<arg<1>>())
|
||||
.function("bindBuffer", select_overload<void(uint32_t, Buffer *, uint32_t, AccessFlags)>(&DescriptorSet::bindBuffer), allow_raw_pointer<arg<1>>())
|
||||
.function("bindTexture", select_overload<void(uint32_t, Texture *)>(&DescriptorSet::bindTexture), allow_raw_pointer<arg<1>>())
|
||||
.function("bindTexture", select_overload<void(uint32_t, Texture *, uint32_t)>(&DescriptorSet::bindTexture), allow_raw_pointer<arg<1>>())
|
||||
.function("bindSampler", select_overload<void(uint32_t, Sampler *)>(&DescriptorSet::bindSampler), allow_raw_pointer<arg<1>>())
|
||||
.function("bindSampler", select_overload<void(uint32_t, Sampler *, uint32_t)>(&DescriptorSet::bindSampler), allow_raw_pointer<arg<1>>())
|
||||
.function("getBuffer", select_overload<Buffer *(uint32_t) const>(&DescriptorSet::getBuffer), allow_raw_pointers())
|
||||
.function("getBuffer", select_overload<Buffer *(uint32_t, uint32_t) const>(&DescriptorSet::getBuffer), allow_raw_pointers())
|
||||
.function("getTexture", select_overload<Texture *(uint32_t) const>(&DescriptorSet::getTexture), allow_raw_pointers())
|
||||
.function("getTexture", select_overload<Texture *(uint32_t, uint32_t) const>(&DescriptorSet::getTexture), allow_raw_pointers())
|
||||
.function("getSampler", select_overload<Sampler *(uint32_t) const>(&DescriptorSet::getSampler), allow_raw_pointers())
|
||||
.function("getSampler", select_overload<Sampler *(uint32_t, uint32_t) const>(&DescriptorSet::getSampler), allow_raw_pointers())
|
||||
.property("layout", &DescriptorSet::getLayout)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&DescriptorSet::getObjectID));
|
||||
class_<CCWGPUDescriptorSet, base<DescriptorSet>>("CCWGPUDescriptorSet")
|
||||
.property("gpuDescriptorSet", &CCWGPUDescriptorSet::gpuDescriptors, &CCWGPUDescriptorSet::setGpuDescriptors)
|
||||
.constructor<>();
|
||||
|
||||
class_<PipelineLayout>("PipelineLayout")
|
||||
.function("initialize", &PipelineLayout::initialize)
|
||||
.function("destroy", &PipelineLayout::destroy)
|
||||
.property("setLayouts", &PipelineLayout::getSetLayouts)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&PipelineLayout::getObjectID));
|
||||
class_<CCWGPUPipelineLayout, base<PipelineLayout>>("CCWGPUPipelineLayout")
|
||||
.constructor<>();
|
||||
|
||||
class_<Shader>("Shader")
|
||||
.function("destroy", &Shader::destroy)
|
||||
.property("name", &Shader::getName)
|
||||
.property("attributes", &Shader::getAttributes)
|
||||
.property("blocks", &Shader::getBlocks)
|
||||
.property("samplers", &Shader::getSamplers)
|
||||
.property("stages", &Shader::getStages)
|
||||
.property("buffers", &Shader::getBuffers)
|
||||
.property("samplerTextures", &Shader::getSamplerTextures)
|
||||
.property("textures", &Shader::getTextures)
|
||||
.property("images", &Shader::getImages)
|
||||
.property("subpassInputs", &Shader::getSubpassInputs)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Shader::getObjectID));
|
||||
class_<CCWGPUShader, base<Shader>>("CCWGPUShader")
|
||||
.function("initialize", &CCWGPUShader::initWithWGSL)
|
||||
.function("reflectBinding", &CCWGPUShader::reflectBinding)
|
||||
.constructor<>();
|
||||
|
||||
class_<InputAssembler>("InputAssembler")
|
||||
.function("initialize", &InputAssembler::initialize)
|
||||
.function("destroy", &InputAssembler::destroy)
|
||||
.property("drawInfo", &InputAssembler::getDrawInfo, &InputAssembler::setDrawInfo)
|
||||
.property("vertexCount", &InputAssembler::getVertexCount, &InputAssembler::setVertexCount)
|
||||
.property("firstVertex", &InputAssembler::getFirstVertex, &InputAssembler::setFirstVertex)
|
||||
.property("indexCount", &InputAssembler::getIndexCount, &InputAssembler::setIndexCount)
|
||||
.property("firstIndex", &InputAssembler::getFirstIndex, &InputAssembler::setFirstIndex)
|
||||
.property("vertexOffset", &InputAssembler::getVertexOffset, &InputAssembler::setVertexOffset)
|
||||
.property("instanceCount", &InputAssembler::getInstanceCount, &InputAssembler::setInstanceCount)
|
||||
.property("firstInstance", &InputAssembler::getFirstInstance, &InputAssembler::setFirstInstance)
|
||||
.property("attributesHash", &InputAssembler::getAttributesHash)
|
||||
.property("attributes", &InputAssembler::getAttributes)
|
||||
.property("vertexBuffers", &InputAssembler::getVertexBuffers)
|
||||
.property("indexBuffer", &InputAssembler::getIndexBuffer)
|
||||
.property("indirectBuffer", &InputAssembler::getIndirectBuffer)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&InputAssembler::getObjectID));
|
||||
class_<CCWGPUInputAssembler, base<InputAssembler>>("CCWGPUInputAssembler")
|
||||
.constructor<>();
|
||||
|
||||
class_<CommandBuffer>("CommandBuffer")
|
||||
.function("initialize", &CommandBuffer::initialize)
|
||||
.function("destroy", &CommandBuffer::destroy)
|
||||
.function("end", &CommandBuffer::end)
|
||||
.function("endRenderPass", &CommandBuffer::endRenderPass)
|
||||
.function("setDepthBias", &CommandBuffer::setDepthBias)
|
||||
.function("setBlendConstants", &CommandBuffer::setBlendConstants)
|
||||
.function("setDepthBound", &CommandBuffer::setDepthBound)
|
||||
.function("setStencilWriteMask", &CommandBuffer::setStencilWriteMask)
|
||||
.function("setStencilCompareMask", &CommandBuffer::setStencilCompareMask)
|
||||
.function("nextSubpass", &CommandBuffer::nextSubpass)
|
||||
.function("copyBuffersToTexture", select_overload<void(const uint8_t *const *, Texture *, const BufferTextureCopy *, uint32_t)>(&CommandBuffer::copyBuffersToTexture), allow_raw_pointers())
|
||||
.function("blitTexture", select_overload<void(Texture *, Texture *, const TextureBlit *, uint32_t, Filter)>(&CommandBuffer::blitTexture), allow_raw_pointers())
|
||||
.function("execute", select_overload<void(CommandBuffer *const *, uint32_t)>(&CommandBuffer::execute), allow_raw_pointer<arg<0>>())
|
||||
.function("dispatch", &CommandBuffer::dispatch)
|
||||
.function("begin", select_overload<void(void)>(&CommandBuffer::begin))
|
||||
.function("begin", select_overload<void(RenderPass *)>(&CommandBuffer::begin), allow_raw_pointers())
|
||||
.function("begin", select_overload<void(RenderPass *, uint32_t)>(&CommandBuffer::begin), allow_raw_pointers())
|
||||
.function("begin", select_overload<void(RenderPass *, uint32_t, Framebuffer *)>(&CommandBuffer::begin), allow_raw_pointers())
|
||||
.function("execute", select_overload<void(const CommandBufferList &, uint32_t)>(&CommandBuffer::execute), allow_raw_pointers())
|
||||
.function("blitTexture2", select_overload<void(Texture *, Texture *, const TextureBlitList &, Filter)>(&CommandBuffer::blitTexture), allow_raw_pointers())
|
||||
.function("draw", select_overload<void(InputAssembler *)>(&CommandBuffer::draw), allow_raw_pointers())
|
||||
.function("type", &CommandBuffer::getType)
|
||||
.property("queue", &CommandBuffer::getQueue)
|
||||
.property("numDrawCalls", &CommandBuffer::getNumDrawCalls)
|
||||
.property("numInstances", &CommandBuffer::getNumInstances)
|
||||
.property("numTris", &CommandBuffer::getNumTris)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&CommandBuffer::getObjectID));
|
||||
class_<CCWGPUCommandBuffer, base<CommandBuffer>>("CCWGPUCommandBuffer")
|
||||
.constructor<>()
|
||||
.function("setViewport", select_overload<void(const Viewport &)>(&CCWGPUCommandBuffer::setViewport))
|
||||
.function("setScissor", select_overload<void(const Rect &)>(&CCWGPUCommandBuffer::setScissor))
|
||||
.function("beginRenderPass", select_overload<void(RenderPass *, Framebuffer *, const Rect &, const ColorList &, float, uint32_t)>(&CCWGPUCommandBuffer::beginRenderPass), allow_raw_pointers())
|
||||
.function("bindDescriptorSet", select_overload<void(uint32_t, DescriptorSet *, const std::vector<uint32_t> &)>(&CCWGPUCommandBuffer::bindDescriptorSet), allow_raw_pointers())
|
||||
.function("bindPipelineState", select_overload<void(PipelineState *)>(&CCWGPUCommandBuffer::bindPipelineState), allow_raw_pointer<arg<0>>())
|
||||
.function("bindInputAssembler", select_overload<void(InputAssembler *)>(&CCWGPUCommandBuffer::bindInputAssembler), allow_raw_pointer<arg<0>>())
|
||||
.function("drawByInfo", select_overload<void(const DrawInfo &)>(&CCWGPUCommandBuffer::draw))
|
||||
.function("updateIndirectBuffer", select_overload<void(Buffer *, const DrawInfoList &)>(&CCWGPUCommandBuffer::updateIndirectBuffer), allow_raw_pointers())
|
||||
.function("updateBuffer", select_overload<void(Buffer *, const emscripten::val &v, uint32_t)>(&CCWGPUCommandBuffer::updateBuffer), allow_raw_pointers());
|
||||
|
||||
class_<Queue>("Queue")
|
||||
.function("initialize", &Queue::initialize)
|
||||
.function("destroy", &Queue::destroy)
|
||||
.function("submit", select_overload<void(const CommandBufferList &cmdBuffs)>(&Queue::submit))
|
||||
.property("type", &Queue::getType)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&Queue::getObjectID));
|
||||
class_<CCWGPUQueue, base<Queue>>("CCWGPUQueue")
|
||||
.constructor<>();
|
||||
|
||||
class_<PipelineState>("PipelineState")
|
||||
.function("initialize", &Queue::initialize)
|
||||
.function("destroy", &Queue::destroy)
|
||||
.property("shader", &PipelineState::getShader)
|
||||
.property("pipelineLayout", &PipelineState::getPipelineLayout)
|
||||
.property("primitive", &PipelineState::getPrimitive)
|
||||
.property("rasterizerState", &PipelineState::getRasterizerState)
|
||||
.property("depthStencilState", &PipelineState::getDepthStencilState)
|
||||
.property("blendState", &PipelineState::getBlendState)
|
||||
.property("inputState", &PipelineState::getInputState)
|
||||
.property("dynamicStates", &PipelineState::getDynamicStates)
|
||||
.property("renderPass", &PipelineState::getRenderPass)
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&PipelineState::getObjectID));
|
||||
class_<CCWGPUPipelineState, base<PipelineState>>("CCWGPUPipelineState")
|
||||
.constructor<>();
|
||||
|
||||
class_<GeneralBarrier>("GeneralBarrier")
|
||||
.constructor<GeneralBarrierInfo>()
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&GeneralBarrier::getObjectID));
|
||||
class_<WGPUGeneralBarrier>("WGPUGeneralBarrier")
|
||||
.constructor<GeneralBarrierInfo>();
|
||||
|
||||
class_<BufferBarrier>("BufferBarrier")
|
||||
.constructor<BufferBarrierInfo>()
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&BufferBarrier::getObjectID));
|
||||
class_<WGPUBufferBarrier>("WGPUBufferBarrier")
|
||||
.constructor<BufferBarrierInfo>();
|
||||
|
||||
class_<TextureBarrier>("TextureBarrier")
|
||||
.constructor<TextureBarrierInfo>()
|
||||
.property("objectID", select_overload<uint32_t(void) const>(&TextureBarrier::getObjectID));
|
||||
class_<WGPUTextureBarrier>("WGPUTextureBarrier")
|
||||
.constructor<TextureBarrierInfo>();
|
||||
};
|
||||
} // namespace cc::gfx
|
||||
61
cocos/renderer/gfx-wgpu/WGPUFrameBuffer.cpp
Normal file
61
cocos/renderer/gfx-wgpu/WGPUFrameBuffer.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUFrameBuffer.h"
|
||||
#include "WGPUTexture.h"
|
||||
|
||||
using namespace emscripten;
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
CCWGPUFramebuffer::CCWGPUFramebuffer() : Framebuffer() {
|
||||
}
|
||||
|
||||
CCWGPUFramebuffer::~CCWGPUFramebuffer() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUFramebuffer::doInit(const FramebufferInfo &info) {
|
||||
for (auto *tex : info.colorTextures) {
|
||||
auto *ccTex = static_cast<CCWGPUTexture *>(tex);
|
||||
CCWGPUSwapchain *swapchain = ccTex->swapchain();
|
||||
if (swapchain) {
|
||||
_swapchain = swapchain;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_depthStencilTexture) {
|
||||
CCWGPUSwapchain *swapchain = static_cast<CCWGPUTexture *>(_depthStencilTexture)->swapchain();
|
||||
if (swapchain) {
|
||||
_swapchain = swapchain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUFramebuffer::doDestroy() {
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
57
cocos/renderer/gfx-wgpu/WGPUFrameBuffer.h
Normal file
57
cocos/renderer/gfx-wgpu/WGPUFrameBuffer.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "gfx-base/GFXFramebuffer.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CCWGPUSwapchain;
|
||||
|
||||
class CCWGPUFramebuffer final : public Framebuffer {
|
||||
public:
|
||||
CCWGPUFramebuffer();
|
||||
~CCWGPUFramebuffer();
|
||||
|
||||
inline CCWGPUSwapchain *swapchain() { return _swapchain; }
|
||||
|
||||
using Framebuffer::initialize;
|
||||
|
||||
inline void setRenderPass(RenderPass *rp) { _renderPass = rp; }
|
||||
inline void setColorTextures(const TextureList &colors) { _colorTextures = colors; }
|
||||
inline void setDepthStencilTexture(Texture *dsTex) { _depthStencilTexture = dsTex; }
|
||||
|
||||
protected:
|
||||
void doInit(const FramebufferInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUSwapchain *_swapchain = nullptr;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
50
cocos/renderer/gfx-wgpu/WGPUInputAssembler.cpp
Normal file
50
cocos/renderer/gfx-wgpu/WGPUInputAssembler.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUInputAssembler.h"
|
||||
#include "WGPUObject.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
CCWGPUInputAssembler::CCWGPUInputAssembler() : InputAssembler() {
|
||||
}
|
||||
|
||||
CCWGPUInputAssembler::~CCWGPUInputAssembler() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUInputAssembler::doInit(const InputAssemblerInfo &info) {
|
||||
_gpuInputAssemblerObj = ccnew CCWGPUInputAssemblerObject;
|
||||
}
|
||||
|
||||
void CCWGPUInputAssembler::doDestroy() {
|
||||
if (_gpuInputAssemblerObj) {
|
||||
delete _gpuInputAssemblerObj;
|
||||
_gpuInputAssemblerObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
54
cocos/renderer/gfx-wgpu/WGPUInputAssembler.h
Normal file
54
cocos/renderer/gfx-wgpu/WGPUInputAssembler.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "gfx-base/GFXInputAssembler.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CCWGPUInputAssemblerObject;
|
||||
class CCWGPUBuffer;
|
||||
class CCWGPUInputAssembler final : public InputAssembler {
|
||||
public:
|
||||
CCWGPUInputAssembler();
|
||||
~CCWGPUInputAssembler();
|
||||
|
||||
using InputAssembler::destroy;
|
||||
using InputAssembler::initialize;
|
||||
|
||||
inline CCWGPUInputAssemblerObject *gpuInputAssemblerObject() { return _gpuInputAssemblerObj; }
|
||||
|
||||
protected:
|
||||
void doInit(const InputAssemblerInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUInputAssemblerObject *_gpuInputAssemblerObj = nullptr;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
415
cocos/renderer/gfx-wgpu/WGPUObject.h
Normal file
415
cocos/renderer/gfx-wgpu/WGPUObject.h
Normal file
@@ -0,0 +1,415 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 <emscripten/html5_webgpu.h>
|
||||
#include <utility>
|
||||
#include "WGPUDef.h"
|
||||
#include "base/Utils.h"
|
||||
#include "base/std/container/map.h"
|
||||
#include "base/std/container/set.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
#include "base/threading/Semaphore.h"
|
||||
#include "gfx-base/GFXDef.h"
|
||||
|
||||
class WGPURenderPassDescriptor;
|
||||
class WGPUComputePassDescriptor;
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace gfx {
|
||||
|
||||
constexpr uint8_t CC_WGPU_MAX_ATTACHMENTS = 16;
|
||||
constexpr decltype(nullptr) wgpuDefaultHandle = nullptr;
|
||||
constexpr ccstd::hash_t WGPU_HASH_SEED = 0x811C9DC5;
|
||||
constexpr uint8_t CC_WGPU_MAX_FRAME_COUNT = 3;
|
||||
|
||||
const DescriptorType COMBINED_ST_IN_USE = DescriptorType::SAMPLER_TEXTURE | DescriptorType::INPUT_ATTACHMENT;
|
||||
|
||||
class CCWGPUTexture;
|
||||
class CCWGPUBuffer;
|
||||
class CCWGPUSampler;
|
||||
class CCWGPUQueue;
|
||||
class CCWGPUPipelineState;
|
||||
class CCWGPUDescriptorSet;
|
||||
class CCWGPUInputAssembler;
|
||||
|
||||
struct CCWGPUResource {
|
||||
CCWGPUBuffer *uniformBuffer = nullptr;
|
||||
CCWGPUBuffer *storageBuffer = nullptr;
|
||||
|
||||
CCWGPUTexture *commonTexture = nullptr;
|
||||
CCWGPUTexture *storageTexture = nullptr;
|
||||
|
||||
CCWGPUSampler *filterableSampler = nullptr;
|
||||
CCWGPUSampler *unfilterableSampler = nullptr;
|
||||
};
|
||||
|
||||
struct CCWGPUInstanceObject {
|
||||
WGPUInstance wgpuInstance = wgpuDefaultHandle;
|
||||
WGPUSurface wgpuSurface = wgpuDefaultHandle;
|
||||
WGPUAdapter wgpuAdapter = wgpuDefaultHandle;
|
||||
};
|
||||
|
||||
struct CCWGPUDeviceObject {
|
||||
WGPUDevice wgpuDevice = wgpuDefaultHandle;
|
||||
WGPUQueue wgpuQueue = wgpuDefaultHandle;
|
||||
|
||||
CCWGPUInstanceObject instance;
|
||||
CCWGPUResource defaultResources;
|
||||
};
|
||||
|
||||
struct CCWGPUSwapchainObject {
|
||||
WGPUSwapChain wgpuSwapChain = wgpuDefaultHandle;
|
||||
WGPUSurface wgpuSurface = wgpuDefaultHandle;
|
||||
|
||||
CCWGPUTexture *swapchainColor = nullptr;
|
||||
CCWGPUTexture *swapchainDepthStencil = nullptr;
|
||||
};
|
||||
|
||||
struct CCWGPURenderPassObject {
|
||||
RenderPassInfo info;
|
||||
ccstd::string label;
|
||||
uint8_t sampleCount = 1;
|
||||
WGPURenderPassDescriptor *wgpuRenderPassDesc = wgpuDefaultHandle;
|
||||
};
|
||||
|
||||
struct CCWGPUTextureObject {
|
||||
WGPUTexture wgpuTexture = wgpuDefaultHandle;
|
||||
WGPUTextureView wgpuTextureView = wgpuDefaultHandle;
|
||||
WGPUTextureView selfView = wgpuDefaultHandle;
|
||||
std::vector<WGPUTextureView> planeViews;
|
||||
};
|
||||
|
||||
// The indirect drawIndexed parameters encoded in the buffer must be a tightly packed block
|
||||
// of five 32-bit unsigned integer values (20 bytes total), given in the same order as the arguments for drawIndexed().
|
||||
// let drawIndexedIndirectParameters = new Uint32Array(5);
|
||||
// drawIndexedIndirectParameters[0] = indexCount;
|
||||
// drawIndexedIndirectParameters[1] = instanceCount;
|
||||
// drawIndexedIndirectParameters[2] = firstIndex;
|
||||
// drawIndexedIndirectParameters[3] = baseVertex;
|
||||
// drawIndexedIndirectParameters[4] = 0; // firstInstance. Must be 0.
|
||||
struct CCWGPUDrawIndexedIndirectObject {
|
||||
uint32_t indexCount = 0;
|
||||
uint32_t instanceCount = 0;
|
||||
uint32_t firstIndex = 0;
|
||||
uint32_t baseVertex = 0;
|
||||
uint32_t firstInstance = 0;
|
||||
};
|
||||
static_assert(sizeof(CCWGPUDrawIndexedIndirectObject) == 20, "WGPU drawIndexedIndirect structure validation failed!");
|
||||
|
||||
// The indirect draw parameters encoded in the buffer must be a tightly packed block
|
||||
// of four 32-bit unsigned integer values (16 bytes total), given in the same order as the arguments for draw().
|
||||
|
||||
// let drawIndirectParameters = new Uint32Array(4);
|
||||
// drawIndirectParameters[0] = vertexCount;
|
||||
// drawIndirectParameters[1] = instanceCount;
|
||||
// drawIndirectParameters[2] = firstVertex;
|
||||
// drawIndirectParameters[3] = 0; // firstInstance. Must be 0.
|
||||
struct CCWGPUDrawIndirectObject {
|
||||
uint32_t vertexCount = 0;
|
||||
uint32_t instanceCount = 0;
|
||||
uint32_t firstIndex = 0;
|
||||
uint32_t firstInstance = 0;
|
||||
};
|
||||
static_assert(sizeof(CCWGPUDrawIndirectObject) == 16, "WGPU drawIndirect structure validation failed!");
|
||||
|
||||
struct CCWGPUBufferObject {
|
||||
WGPUBuffer wgpuBuffer = wgpuDefaultHandle;
|
||||
ccstd::vector<CCWGPUDrawIndexedIndirectObject> indexedIndirectObjs;
|
||||
ccstd::vector<CCWGPUDrawIndirectObject> indirectObjs;
|
||||
bool mapped = false;
|
||||
bool hasDynamicOffsets = false;
|
||||
};
|
||||
|
||||
struct CCWGPUSamplerObject {
|
||||
WGPUSampler wgpuSampler = wgpuDefaultHandle;
|
||||
|
||||
WGPUAddressMode addressModeU = WGPUAddressMode_Repeat;
|
||||
WGPUAddressMode addressModeV = WGPUAddressMode_Repeat;
|
||||
WGPUAddressMode addressModeW = WGPUAddressMode_Repeat;
|
||||
WGPUFilterMode magFilter = WGPUFilterMode_Linear;
|
||||
WGPUFilterMode minFilter = WGPUFilterMode_Linear;
|
||||
WGPUFilterMode mipmapFilter = WGPUFilterMode_Linear;
|
||||
float lodMinClamp = 0.1f;
|
||||
float lodMaxClamp = 1000.0f;
|
||||
WGPUCompareFunction compare = WGPUCompareFunction_Always;
|
||||
uint16_t maxAnisotropy = 0;
|
||||
};
|
||||
|
||||
struct CCWGPUBindGroupLayoutObject {
|
||||
WGPUBindGroupLayout bindGroupLayout = wgpuDefaultHandle;
|
||||
ccstd::map<uint32_t, WGPUBindGroupLayoutEntry> bindGroupLayoutEntries;
|
||||
};
|
||||
|
||||
struct CCWGPUBindGroupObject {
|
||||
WGPUBindGroup bindgroup = wgpuDefaultHandle;
|
||||
ccstd::vector<WGPUBindGroupEntry> bindGroupEntries;
|
||||
ccstd::set<uint8_t> bindingSet; // bindingInDesc
|
||||
ccstd::set<uint8_t> bindingInShader; // bindingInShader
|
||||
};
|
||||
|
||||
struct CCWGPUPipelineLayoutObject {
|
||||
WGPUPipelineLayout wgpuPipelineLayout = wgpuDefaultHandle;
|
||||
};
|
||||
|
||||
struct CCWGPUPipelineStateObject {
|
||||
WGPURenderPipeline wgpuRenderPipeline = wgpuDefaultHandle;
|
||||
WGPUComputePipeline wgpuComputePipeline = wgpuDefaultHandle;
|
||||
|
||||
ccstd::vector<WGPUVertexAttribute> redundantAttr;
|
||||
uint32_t maxAttrLength = 0;
|
||||
};
|
||||
|
||||
using BindingList = ccstd::vector<uint8_t>;
|
||||
struct CCWGPUShaderObject {
|
||||
ccstd::string name;
|
||||
WGPUShaderModule wgpuShaderVertexModule = wgpuDefaultHandle;
|
||||
WGPUShaderModule wgpuShaderFragmentModule = wgpuDefaultHandle;
|
||||
WGPUShaderModule wgpuShaderComputeModule = wgpuDefaultHandle;
|
||||
|
||||
ccstd::vector<BindingList> bindings;
|
||||
};
|
||||
|
||||
struct CCWGPUInputAssemblerObject {
|
||||
WGPUVertexState wgpuVertexState;
|
||||
};
|
||||
|
||||
struct CCWGPUQueueObject {
|
||||
WGPUQueue wgpuQueue = wgpuDefaultHandle;
|
||||
QueueType type = QueueType::GRAPHICS;
|
||||
};
|
||||
|
||||
struct CCWGPUDescriptorSetObject {
|
||||
CCWGPUDescriptorSet *descriptorSet = nullptr;
|
||||
uint32_t dynamicOffsetCount = 0;
|
||||
const uint32_t *dynamicOffsets = nullptr;
|
||||
};
|
||||
|
||||
struct CCWGPUStencilMasks {
|
||||
uint32_t writeMask = 0;
|
||||
uint32_t compareRef = 0;
|
||||
uint32_t compareMask = 0;
|
||||
};
|
||||
|
||||
struct CCWGPUStateCache {
|
||||
CCWGPUPipelineState *pipelineState = nullptr;
|
||||
CCWGPUInputAssembler *inputAssembler = nullptr;
|
||||
|
||||
float depthBiasConstant = 0.0f;
|
||||
float depthBiasClamp = 0.0f;
|
||||
float depthBiasSlope = 0.0f;
|
||||
float depthMinBound = 0.0f;
|
||||
float depthMaxBound = 100.0f;
|
||||
|
||||
Color blendConstants;
|
||||
Viewport viewport;
|
||||
Rect rect;
|
||||
|
||||
uint32_t minAttachmentWidth = 0;
|
||||
uint32_t minAttachmentHeight = 0;
|
||||
|
||||
ccstd::vector<CCWGPUDescriptorSetObject> descriptorSets;
|
||||
ccstd::map<StencilFace, CCWGPUStencilMasks> stencilMasks;
|
||||
};
|
||||
|
||||
struct CCWGPUCommandBufferObject {
|
||||
bool renderPassBegan = false;
|
||||
|
||||
WGPUCommandBuffer wgpuCommandBuffer = wgpuDefaultHandle;
|
||||
WGPUCommandEncoder wgpuCommandEncoder = wgpuDefaultHandle;
|
||||
WGPURenderPassEncoder wgpuRenderPassEncoder = wgpuDefaultHandle;
|
||||
WGPUComputePassEncoder wgpuComputeEncoder = wgpuDefaultHandle;
|
||||
CommandBufferType type = CommandBufferType::PRIMARY;
|
||||
CCWGPUQueue *queue = nullptr;
|
||||
|
||||
WGPURenderPassDescriptor renderPassDescriptor;
|
||||
CCWGPUStateCache stateCache;
|
||||
|
||||
ccstd::vector<WGPUCommandBuffer> computeCmdBuffs;
|
||||
ccstd::unordered_map<uint32_t, CCWGPUBuffer *> redundantVertexBufferMap;
|
||||
};
|
||||
|
||||
struct CCWGPUQueryPoolObject {
|
||||
QueryType type = QueryType::OCCLUSION;
|
||||
uint32_t maxQueryObjects = 0;
|
||||
ccstd::vector<uint32_t> idPool;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RecycleBin {
|
||||
public:
|
||||
RecycleBin() = default;
|
||||
~RecycleBin() = default;
|
||||
RecycleBin(const RecycleBin &) = delete;
|
||||
RecycleBin &operator=(const RecycleBin &) = delete;
|
||||
|
||||
void collect(T t) {
|
||||
_recycleBin.emplace(t);
|
||||
}
|
||||
|
||||
void purge() {
|
||||
for (auto &t : _recycleBin) {
|
||||
purge(t);
|
||||
}
|
||||
_recycleBin.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void purge(T t);
|
||||
|
||||
ccstd::set<T> _recycleBin;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline void RecycleBin<WGPUBuffer>::purge(WGPUBuffer buffer) {
|
||||
wgpuBufferDestroy(buffer);
|
||||
wgpuBufferRelease(buffer);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void RecycleBin<WGPUQuerySet>::purge(WGPUQuerySet querySet) {
|
||||
wgpuQuerySetDestroy(querySet);
|
||||
wgpuQuerySetRelease(querySet);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void RecycleBin<WGPUTexture>::purge(WGPUTexture texture) {
|
||||
wgpuTextureDestroy(texture);
|
||||
wgpuTextureRelease(texture);
|
||||
}
|
||||
|
||||
struct CCWGPURecycleBin {
|
||||
RecycleBin<WGPUBuffer> bufferBin;
|
||||
RecycleBin<WGPUTexture> textureBin;
|
||||
RecycleBin<WGPUQuerySet> queryBin;
|
||||
};
|
||||
|
||||
namespace {
|
||||
inline void onStagingBufferMapDone(WGPUBufferMapAsyncStatus status, void *userdata) {
|
||||
if (status == WGPUBufferMapAsyncStatus_Success) {
|
||||
auto *semaphore = static_cast<Semaphore *>(userdata);
|
||||
semaphore->signal();
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
constexpr uint32_t INIT_BUFFER_SIZE = 1024 * 1024 * 1; // 1MB
|
||||
|
||||
class CCWGPUStagingBuffer {
|
||||
CCWGPUStagingBuffer(const CCWGPUStagingBuffer &) = delete;
|
||||
CCWGPUStagingBuffer &operator=(const CCWGPUStagingBuffer &) = delete;
|
||||
CCWGPUStagingBuffer() = default;
|
||||
~CCWGPUStagingBuffer() = default;
|
||||
|
||||
public:
|
||||
explicit CCWGPUStagingBuffer(WGPUDevice device, const std::function<void(WGPUBuffer)> &recycleFunc)
|
||||
: _device(device), _size(INIT_BUFFER_SIZE), _recycleFunc(recycleFunc) {
|
||||
WGPUBufferDescriptor desc = {
|
||||
.label = "staging buffer",
|
||||
.usage = WGPUBufferUsage_CopySrc | WGPUBufferUsage_MapWrite,
|
||||
.size = _size,
|
||||
.mappedAtCreation = true,
|
||||
};
|
||||
_buffer = wgpuDeviceCreateBuffer(device, &desc);
|
||||
_mappedData = wgpuBufferGetMappedRange(_buffer, 0, _size);
|
||||
}
|
||||
|
||||
uint32_t alloc(uint32_t size) {
|
||||
// 1. what if it's still unmapped
|
||||
if (!_mapped) {
|
||||
Semaphore sem{0};
|
||||
wgpuBufferMapAsync(_buffer, WGPUMapMode_Write, 0, _size, onStagingBufferMapDone, &sem);
|
||||
sem.wait();
|
||||
_mappedData = wgpuBufferGetMappedRange(_buffer, 0, _size);
|
||||
_mapped = true;
|
||||
}
|
||||
|
||||
const auto oldOffset = _offset;
|
||||
if (_offset + size > _size) {
|
||||
const auto oldBuffer = _buffer;
|
||||
const auto oldSize = _size;
|
||||
const auto *oldMappedData = _mappedData;
|
||||
|
||||
_size = utils::nextPOT(_offset + size);
|
||||
WGPUBufferDescriptor desc = {
|
||||
.label = "staging buffer",
|
||||
.usage = WGPUBufferUsage_CopySrc | WGPUBufferUsage_MapWrite,
|
||||
.size = _size,
|
||||
.mappedAtCreation = true,
|
||||
};
|
||||
_buffer = wgpuDeviceCreateBuffer(_device, &desc);
|
||||
_mappedData = wgpuBufferGetMappedRange(_buffer, 0, _size);
|
||||
_offset = 0;
|
||||
|
||||
if (_mapped) {
|
||||
memcpy(_mappedData, oldMappedData, oldSize);
|
||||
_offset = oldOffset;
|
||||
} else {
|
||||
// do nothing, unmap means this buffer has flush its data to gpu
|
||||
}
|
||||
_recycleFunc(oldBuffer);
|
||||
}
|
||||
_offset += size;
|
||||
return oldOffset;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (_mapped) {
|
||||
wgpuBufferUnmap(_buffer);
|
||||
}
|
||||
if (_recycleFunc) {
|
||||
_recycleFunc(_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void unmap() {
|
||||
if (_mapped) {
|
||||
wgpuBufferUnmap(_buffer);
|
||||
_mapped = false;
|
||||
}
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
void *getMappedData(uint32_t offset) {
|
||||
return static_cast<uint8_t *>(_mappedData) + offset;
|
||||
}
|
||||
|
||||
WGPUBuffer getBuffer() {
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
WGPUDevice _device{wgpuDefaultHandle};
|
||||
WGPUBuffer _buffer{wgpuDefaultHandle};
|
||||
void *_mappedData{nullptr};
|
||||
uint32_t _size{0};
|
||||
uint32_t _offset{0};
|
||||
std::function<void(WGPUBuffer)> _recycleFunc;
|
||||
bool _mapped{false};
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
||||
} // namespace cc
|
||||
99
cocos/renderer/gfx-wgpu/WGPUPipelineLayout.cpp
Normal file
99
cocos/renderer/gfx-wgpu/WGPUPipelineLayout.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUPipelineLayout.h"
|
||||
#include <emscripten/html5_webgpu.h>
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
ccstd::map<ccstd::hash_t, void *> CCWGPUPipelineLayout::layoutMap;
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
CCWGPUPipelineLayout::CCWGPUPipelineLayout() : PipelineLayout() {
|
||||
}
|
||||
|
||||
CCWGPUPipelineLayout::~CCWGPUPipelineLayout() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUPipelineLayout::doInit(const PipelineLayoutInfo &info) {
|
||||
_gpuPipelineLayoutObj = ccnew CCWGPUPipelineLayoutObject;
|
||||
}
|
||||
|
||||
void CCWGPUPipelineLayout::prepare(const ccstd::set<uint8_t> &setInUse) {
|
||||
ccstd::hash_t hash = _setLayouts.size() * 2 + 1;
|
||||
ccstd::hash_combine(hash, _setLayouts.size());
|
||||
ccstd::vector<WGPUBindGroupLayout> layouts;
|
||||
for (size_t i = 0; i < _setLayouts.size(); i++) {
|
||||
auto *descriptorSetLayout = static_cast<CCWGPUDescriptorSetLayout *>(_setLayouts[i]);
|
||||
if (setInUse.find(i) == setInUse.end()) {
|
||||
// give it default bindgrouplayout if not in use
|
||||
layouts.push_back(static_cast<WGPUBindGroupLayout>(CCWGPUDescriptorSetLayout::defaultBindGroupLayout()));
|
||||
ccstd::hash_combine(hash, i);
|
||||
ccstd::hash_combine(hash, 9527);
|
||||
} else {
|
||||
if (!descriptorSetLayout->gpuLayoutEntryObject()->bindGroupLayout) {
|
||||
printf("bgl in ppl is null\n");
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
layouts.push_back(descriptorSetLayout->gpuLayoutEntryObject()->bindGroupLayout);
|
||||
ccstd::hash_combine(hash, i);
|
||||
ccstd::hash_combine(hash, descriptorSetLayout->getHash());
|
||||
}
|
||||
}
|
||||
|
||||
_hash = hash;
|
||||
|
||||
WGPUPipelineLayoutDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.bindGroupLayoutCount = layouts.size(),
|
||||
.bindGroupLayouts = layouts.data(),
|
||||
};
|
||||
if (layoutMap.find(hash) != layoutMap.end()) {
|
||||
_gpuPipelineLayoutObj->wgpuPipelineLayout = static_cast<WGPUPipelineLayout>(layoutMap[hash]);
|
||||
} else {
|
||||
_gpuPipelineLayoutObj->wgpuPipelineLayout = wgpuDeviceCreatePipelineLayout(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
layoutMap.emplace(hash, _gpuPipelineLayoutObj->wgpuPipelineLayout);
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUPipelineLayout::doDestroy() {
|
||||
if (_gpuPipelineLayoutObj) {
|
||||
if (_gpuPipelineLayoutObj->wgpuPipelineLayout) {
|
||||
wgpuPipelineLayoutRelease(_gpuPipelineLayoutObj->wgpuPipelineLayout);
|
||||
}
|
||||
delete _gpuPipelineLayoutObj;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
71
cocos/renderer/gfx-wgpu/WGPUPipelineLayout.h
Normal file
71
cocos/renderer/gfx-wgpu/WGPUPipelineLayout.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "WGPUUtils.h"
|
||||
#include "base/std/container/map.h"
|
||||
#include "base/std/container/set.h"
|
||||
#include "gfx-base/GFXPipelineLayout.h"
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUPipelineLayoutObject;
|
||||
class DescriptorSet;
|
||||
|
||||
class CCWGPUPipelineLayout final : public PipelineLayout {
|
||||
public:
|
||||
CCWGPUPipelineLayout();
|
||||
~CCWGPUPipelineLayout();
|
||||
|
||||
inline CCWGPUPipelineLayoutObject *gpuPipelineLayoutObject() { return _gpuPipelineLayoutObj; }
|
||||
|
||||
// bindgroup not ready yet so delay creation
|
||||
void prepare(const ccstd::set<uint8_t> &setInUse);
|
||||
|
||||
const ccstd::vector<void *> &layouts() const { return _bgLayouts; }
|
||||
const ccstd::vector<void *> &cclayouts() const { return _ccbgLayouts; }
|
||||
|
||||
static ccstd::map<ccstd::hash_t, void *> layoutMap;
|
||||
|
||||
inline ccstd::hash_t getHash() const { return _hash; }
|
||||
|
||||
protected:
|
||||
void doInit(const PipelineLayoutInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUPipelineLayoutObject *_gpuPipelineLayoutObj = nullptr;
|
||||
|
||||
ccstd::vector<void *> _bgLayouts;
|
||||
ccstd::vector<void *> _ccbgLayouts;
|
||||
|
||||
ccstd::hash_t _hash{0};
|
||||
|
||||
friend void createPipelineLayoutFallback(const ccstd::vector<DescriptorSet *> &descriptorSets, PipelineLayout *pipelineLayout, bool skipEmpty);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
418
cocos/renderer/gfx-wgpu/WGPUPipelineState.cpp
Normal file
418
cocos/renderer/gfx-wgpu/WGPUPipelineState.cpp
Normal file
@@ -0,0 +1,418 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUPipelineState.h"
|
||||
#include <emscripten/html5_webgpu.h>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUPipelineLayout.h"
|
||||
#include "WGPURenderPass.h"
|
||||
#include "WGPUShader.h"
|
||||
#include "WGPUUtils.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
ccstd::map<ccstd::hash_t, void *> CCWGPUPipelineState::pipelineMap;
|
||||
|
||||
namespace {
|
||||
using ccstd::hash_combine;
|
||||
ccstd::hash_t hash(const WGPURenderPipelineDescriptor &desc) {
|
||||
ccstd::hash_t hash = 9527;
|
||||
hash_combine(hash, desc.layout);
|
||||
hash_combine(hash, desc.vertex.module);
|
||||
hash_combine(hash, desc.vertex.entryPoint);
|
||||
hash_combine(hash, desc.vertex.constantCount);
|
||||
for (uint32_t i = 0; i < desc.vertex.constantCount; ++i) {
|
||||
hash_combine(hash, desc.vertex.constants[i].key);
|
||||
hash_combine(hash, desc.vertex.constants[i].value);
|
||||
}
|
||||
|
||||
hash_combine(hash, desc.vertex.bufferCount);
|
||||
for (size_t i = 0; i < desc.vertex.bufferCount; ++i) {
|
||||
const auto &buffer = desc.vertex.buffers[i];
|
||||
hash_combine(hash, buffer.arrayStride);
|
||||
hash_combine(hash, buffer.stepMode);
|
||||
hash_combine(hash, buffer.attributeCount);
|
||||
for (size_t j = 0; j < buffer.attributeCount; ++j) {
|
||||
const auto &attribute = buffer.attributes[j];
|
||||
hash_combine(hash, attribute.shaderLocation);
|
||||
hash_combine(hash, attribute.offset);
|
||||
hash_combine(hash, attribute.format);
|
||||
}
|
||||
}
|
||||
|
||||
hash_combine(hash, desc.primitive.topology);
|
||||
hash_combine(hash, desc.primitive.stripIndexFormat);
|
||||
hash_combine(hash, desc.primitive.frontFace);
|
||||
hash_combine(hash, desc.primitive.cullMode);
|
||||
|
||||
if (desc.depthStencil) {
|
||||
hash_combine(hash, desc.depthStencil->format);
|
||||
hash_combine(hash, desc.depthStencil->depthWriteEnabled);
|
||||
hash_combine(hash, desc.depthStencil->depthCompare);
|
||||
hash_combine(hash, desc.depthStencil->stencilFront.compare);
|
||||
hash_combine(hash, desc.depthStencil->stencilFront.failOp);
|
||||
hash_combine(hash, desc.depthStencil->stencilFront.depthFailOp);
|
||||
hash_combine(hash, desc.depthStencil->stencilFront.passOp);
|
||||
hash_combine(hash, desc.depthStencil->stencilBack.compare);
|
||||
hash_combine(hash, desc.depthStencil->stencilBack.failOp);
|
||||
hash_combine(hash, desc.depthStencil->stencilBack.depthFailOp);
|
||||
hash_combine(hash, desc.depthStencil->stencilBack.passOp);
|
||||
hash_combine(hash, desc.depthStencil->stencilReadMask);
|
||||
hash_combine(hash, desc.depthStencil->stencilWriteMask);
|
||||
hash_combine(hash, desc.depthStencil->depthBias);
|
||||
hash_combine(hash, desc.depthStencil->depthBiasSlopeScale);
|
||||
hash_combine(hash, desc.depthStencil->depthBiasClamp);
|
||||
}
|
||||
|
||||
hash_combine(hash, desc.multisample.count);
|
||||
hash_combine(hash, desc.multisample.mask);
|
||||
hash_combine(hash, desc.multisample.alphaToCoverageEnabled);
|
||||
|
||||
if (desc.fragment) {
|
||||
hash_combine(hash, desc.fragment->module);
|
||||
hash_combine(hash, desc.fragment->entryPoint);
|
||||
hash_combine(hash, desc.fragment->constantCount);
|
||||
for (uint32_t i = 0; i < desc.fragment->constantCount; ++i) {
|
||||
hash_combine(hash, desc.fragment->constants[i].key);
|
||||
hash_combine(hash, desc.fragment->constants[i].value);
|
||||
}
|
||||
|
||||
hash_combine(hash, desc.fragment->targetCount);
|
||||
for (uint32_t i = 0; i < desc.fragment->targetCount; ++i) {
|
||||
hash_combine(hash, desc.fragment->targets[i].format);
|
||||
if (desc.fragment->targets[i].blend) {
|
||||
hash_combine(hash, desc.fragment->targets[i].blend->color.operation);
|
||||
hash_combine(hash, desc.fragment->targets[i].blend->color.srcFactor);
|
||||
hash_combine(hash, desc.fragment->targets[i].blend->color.dstFactor);
|
||||
hash_combine(hash, desc.fragment->targets[i].blend->alpha.operation);
|
||||
hash_combine(hash, desc.fragment->targets[i].blend->alpha.srcFactor);
|
||||
hash_combine(hash, desc.fragment->targets[i].blend->alpha.dstFactor);
|
||||
}
|
||||
hash_combine(hash, desc.fragment->targets[i].writeMask);
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
ccstd::hash_t hash(const WGPUComputePipelineDescriptor &desc) {
|
||||
ccstd::hash_t hash = 9527;
|
||||
hash_combine(hash, desc.layout);
|
||||
// hash_combine(hash, desc.compute);
|
||||
return hash;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CCWGPUPipelineState::CCWGPUPipelineState() : PipelineState() {
|
||||
}
|
||||
|
||||
CCWGPUPipelineState::~CCWGPUPipelineState() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUPipelineState::doInit(const PipelineStateInfo &info) {
|
||||
_gpuPipelineStateObj = ccnew CCWGPUPipelineStateObject;
|
||||
}
|
||||
|
||||
void CCWGPUPipelineState::check(RenderPass *renderPass, bool forceUpdate) {
|
||||
if (_renderPass != renderPass) {
|
||||
_renderPass = renderPass;
|
||||
// _forceUpdate = true;
|
||||
}
|
||||
_forceUpdate |= forceUpdate;
|
||||
}
|
||||
|
||||
void CCWGPUPipelineState::prepare(const ccstd::set<uint8_t> &setInUse) {
|
||||
auto *pipelineLayout = static_cast<CCWGPUPipelineLayout *>(_pipelineLayout);
|
||||
|
||||
const DepthStencilAttachment &dsAttachment = _renderPass->getDepthStencilAttachment();
|
||||
if (_bindPoint == PipelineBindPoint::GRAPHICS) {
|
||||
if (_gpuPipelineStateObj->wgpuRenderPipeline && !_forceUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_gpuPipelineStateObj->redundantAttr.empty()) {
|
||||
_gpuPipelineStateObj->redundantAttr.clear();
|
||||
}
|
||||
|
||||
auto maxStreamAttr = std::max_element(_inputState.attributes.begin(), _inputState.attributes.end(), [&](const Attribute &lhs, const Attribute &rhs) {
|
||||
return lhs.stream < rhs.stream;
|
||||
});
|
||||
|
||||
auto longestAttr = std::max_element(_inputState.attributes.begin(), _inputState.attributes.end(), [&](const Attribute &lhs, const Attribute &rhs) {
|
||||
return GFX_FORMAT_INFOS[static_cast<uint32_t>(lhs.format)].size < GFX_FORMAT_INFOS[static_cast<uint32_t>(rhs.format)].size;
|
||||
});
|
||||
uint8_t mostToleranceStream = (*longestAttr).stream;
|
||||
|
||||
const uint8_t streamCount = (*maxStreamAttr).stream + 1;
|
||||
|
||||
ccstd::vector<WGPUVertexBufferLayout> vbLayouts(streamCount);
|
||||
ccstd::vector<ccstd::vector<WGPUVertexAttribute>> wgpuAttrsVec(streamCount);
|
||||
|
||||
const AttributeList &attrs = _shader->getAttributes();
|
||||
uint64_t offset[256] = {0};
|
||||
// ccstd::vector<WGPUVertexAttribute> wgpuAttrs;
|
||||
|
||||
for (size_t i = 0; i < _inputState.attributes.size(); ++i) {
|
||||
const auto &attr = _inputState.attributes[i];
|
||||
const auto &attrName = attr.name;
|
||||
auto iter = std::find_if(attrs.begin(), attrs.end(), [attrName](const Attribute &attr) {
|
||||
return strcmp(attrName.c_str(), attr.name.c_str()) == 0;
|
||||
});
|
||||
if (iter != attrs.end()) {
|
||||
Format format = attr.format;
|
||||
WGPUVertexAttribute attrInfo = {
|
||||
.format = toWGPUVertexFormat(format),
|
||||
.offset = offset[attr.stream],
|
||||
.shaderLocation = (*iter).location,
|
||||
};
|
||||
wgpuAttrsVec[attr.stream].push_back(attrInfo);
|
||||
offset[attr.stream] += GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].size;
|
||||
vbLayouts[attr.stream].stepMode = attr.isInstanced ? WGPUVertexStepMode_Instance : WGPUVertexStepMode_Vertex;
|
||||
} else {
|
||||
// all none-input attr are put in 1st buffer layout with offset = 0;
|
||||
Format format = attr.format;
|
||||
offset[attr.stream] += GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].size;
|
||||
}
|
||||
}
|
||||
|
||||
// printf("cr shname %s %d\n", _shader->getName().c_str(), streamCount);
|
||||
// wgpuAttrsVec[0] ∪ wgpuAttrsVec[1] ∪ ... ∪ wgpuAttrsVec[n] == shader.attrs
|
||||
for (size_t i = 0; i < attrs.size(); i++) {
|
||||
ccstd::string attrName = attrs[i].name;
|
||||
auto iter = std::find_if(_inputState.attributes.begin(), _inputState.attributes.end(), [attrName](const Attribute &attr) {
|
||||
return strcmp(attrName.c_str(), attr.name.c_str()) == 0;
|
||||
});
|
||||
|
||||
if (iter == _inputState.attributes.end()) {
|
||||
// all none-input attr are put in 1st buffer layout with offset = 0;
|
||||
Format format = attrs[i].format;
|
||||
WGPUVertexAttribute attr = {
|
||||
.format = toWGPUVertexFormat(format),
|
||||
.offset = 0,
|
||||
.shaderLocation = attrs[i].location,
|
||||
};
|
||||
|
||||
if (GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].size > GFX_FORMAT_INFOS[static_cast<uint32_t>((*longestAttr).format)].size) {
|
||||
// printf("found attr %s %s in shader exceed size of longest attr %s %s\n", attrName.c_str(), GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].name.c_str(),
|
||||
// (*longestAttr).name.c_str(), GFX_FORMAT_INFOS[static_cast<uint32_t>((*longestAttr).format)].name.c_str());
|
||||
_gpuPipelineStateObj->redundantAttr.push_back(attr);
|
||||
if (GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].size > _gpuPipelineStateObj->maxAttrLength) {
|
||||
_gpuPipelineStateObj->maxAttrLength = GFX_FORMAT_INFOS[static_cast<uint32_t>(format)].size;
|
||||
}
|
||||
} else {
|
||||
wgpuAttrsVec[mostToleranceStream].push_back(attr);
|
||||
}
|
||||
}
|
||||
|
||||
// printf("sl %s, %d, %d\n", attrName.c_str(), attrs[i].location, attrs[i].stream);
|
||||
}
|
||||
|
||||
if (_gpuPipelineStateObj->maxAttrLength > 0) {
|
||||
wgpuAttrsVec.push_back(_gpuPipelineStateObj->redundantAttr);
|
||||
vbLayouts.resize(vbLayouts.size() + 1);
|
||||
}
|
||||
// _gpuPipelineStateObj->slotCount = vbLayouts.size();
|
||||
|
||||
// std::set<uint32_t> locSet;
|
||||
for (size_t i = 0; i < wgpuAttrsVec.size(); ++i) {
|
||||
vbLayouts[i].arrayStride = offset[i];
|
||||
vbLayouts[i].attributeCount = static_cast<uint32_t>(wgpuAttrsVec[i].size());
|
||||
vbLayouts[i].attributes = wgpuAttrsVec[i].data();
|
||||
// for (size_t j = 0; j < wgpuAttrsVec[i].size(); ++j) {
|
||||
// printf("wg %d, %llu, %d\n", wgpuAttrsVec[i][j].shaderLocation, wgpuAttrsVec[i][j].offset, wgpuAttrsVec[i][j].format);
|
||||
|
||||
// // if (locSet.find(wgpuAttrsVec[i][j].shaderLocation) != locSet.end() && wgpuAttrsVec[i][j].shaderLocation != 0) {
|
||||
// // printf("duplicate location %d\n", wgpuAttrsVec[i][j].shaderLocation);
|
||||
// // while (1) {
|
||||
// // }
|
||||
// // }
|
||||
// // locSet.insert(wgpuAttrsVec[i][j].shaderLocation);
|
||||
// }
|
||||
}
|
||||
|
||||
WGPUVertexState vertexState = {
|
||||
.nextInChain = nullptr,
|
||||
.module = static_cast<CCWGPUShader *>(_shader)->gpuShaderObject()->wgpuShaderVertexModule,
|
||||
.entryPoint = "main",
|
||||
.bufferCount = vbLayouts.size(),
|
||||
.buffers = vbLayouts.data(),
|
||||
};
|
||||
|
||||
bool stripTopology = (_primitive == PrimitiveMode::LINE_STRIP || _primitive == PrimitiveMode::TRIANGLE_STRIP);
|
||||
|
||||
WGPUPrimitiveState primitiveState = {
|
||||
.nextInChain = nullptr,
|
||||
.topology = toWGPUPrimTopology(_primitive),
|
||||
.stripIndexFormat = stripTopology ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Undefined, // TODO_Zeqiang: ???
|
||||
.frontFace = _rasterizerState.isFrontFaceCCW ? WGPUFrontFace::WGPUFrontFace_CCW : WGPUFrontFace::WGPUFrontFace_CW,
|
||||
.cullMode = _rasterizerState.cullMode == CullMode::FRONT ? WGPUCullMode::WGPUCullMode_Front
|
||||
: _rasterizerState.cullMode == CullMode::BACK ? WGPUCullMode::WGPUCullMode_Back
|
||||
: WGPUCullMode::WGPUCullMode_None,
|
||||
};
|
||||
|
||||
WGPUStencilFaceState stencilFront = {
|
||||
.compare = toWGPUCompareFunction(_depthStencilState.stencilFuncFront),
|
||||
.failOp = toWGPUStencilOperation(_depthStencilState.stencilFailOpFront),
|
||||
.depthFailOp = toWGPUStencilOperation(_depthStencilState.stencilZFailOpFront),
|
||||
.passOp = toWGPUStencilOperation(_depthStencilState.stencilPassOpFront),
|
||||
};
|
||||
WGPUStencilFaceState stencilBack = {
|
||||
.compare = toWGPUCompareFunction(_depthStencilState.stencilFuncBack),
|
||||
.failOp = toWGPUStencilOperation(_depthStencilState.stencilFailOpBack),
|
||||
.depthFailOp = toWGPUStencilOperation(_depthStencilState.stencilZFailOpBack),
|
||||
.passOp = toWGPUStencilOperation(_depthStencilState.stencilPassOpBack),
|
||||
};
|
||||
|
||||
WGPUDepthStencilState dsState = {
|
||||
.nextInChain = nullptr,
|
||||
.format = toWGPUTextureFormat(dsAttachment.format),
|
||||
.depthWriteEnabled = _depthStencilState.depthWrite != 0,
|
||||
.depthCompare = _depthStencilState.depthTest ? toWGPUCompareFunction(_depthStencilState.depthFunc) : WGPUCompareFunction_Always,
|
||||
.stencilFront = stencilFront,
|
||||
.stencilBack = stencilBack,
|
||||
.stencilReadMask = _depthStencilState.stencilReadMaskFront,
|
||||
.stencilWriteMask = _depthStencilState.stencilWriteMaskFront,
|
||||
.depthBias = static_cast<int32_t>(_rasterizerState.depthBias),
|
||||
.depthBiasSlopeScale = _rasterizerState.depthBiasSlop,
|
||||
.depthBiasClamp = _rasterizerState.depthBiasClamp,
|
||||
};
|
||||
|
||||
WGPUMultisampleState msState = {
|
||||
.count = static_cast<CCWGPURenderPass *>(_renderPass)->gpuRenderPassObject()->sampleCount,
|
||||
.mask = 0xFFFFFFFF,
|
||||
.alphaToCoverageEnabled = _blendState.isA2C != 0,
|
||||
};
|
||||
|
||||
const ColorAttachmentList &colors = _renderPass->getColorAttachments();
|
||||
ccstd::vector<WGPUColorTargetState> colorTargetStates(colors.size());
|
||||
|
||||
ccstd::vector<WGPUBlendState> blendState(colors.size());
|
||||
|
||||
for (size_t i = 0, targetIndex = 0; i < colors.size(); i++) {
|
||||
colorTargetStates[i].format = toWGPUTextureFormat(colors[i].format);
|
||||
auto colorBO = _blendState.targets[targetIndex].blendEq;
|
||||
blendState[i].color = {
|
||||
.operation = toWGPUBlendOperation(colorBO),
|
||||
.srcFactor = toWGPUBlendFactor(colorBO == BlendOp::MAX ? BlendFactor::ONE : _blendState.targets[targetIndex].blendSrc),
|
||||
.dstFactor = toWGPUBlendFactor(colorBO == BlendOp::MAX ? BlendFactor::ONE : _blendState.targets[targetIndex].blendDst),
|
||||
};
|
||||
auto alphaBO = _blendState.targets[targetIndex].blendAlphaEq;
|
||||
blendState[i].alpha = {
|
||||
.operation = toWGPUBlendOperation(alphaBO),
|
||||
.srcFactor = toWGPUBlendFactor(alphaBO == BlendOp::MAX ? BlendFactor::ONE : _blendState.targets[targetIndex].blendSrcAlpha),
|
||||
.dstFactor = toWGPUBlendFactor(alphaBO == BlendOp::MAX ? BlendFactor::ONE : _blendState.targets[targetIndex].blendDstAlpha),
|
||||
};
|
||||
// only textureSampleType with float can be blended.
|
||||
colorTargetStates[i].blend = (_blendState.targets[targetIndex].blend && (textureSampleTypeTrait(colors[i].format) == WGPUTextureSampleType_Float)) ? &blendState[i] : nullptr;
|
||||
colorTargetStates[i].writeMask = toWGPUColorWriteMask(_blendState.targets[targetIndex].blendColorMask);
|
||||
if (targetIndex < _blendState.targets.size() - 1) {
|
||||
++targetIndex;
|
||||
}
|
||||
}
|
||||
|
||||
WGPUFragmentState fragmentState = {
|
||||
.module = static_cast<CCWGPUShader *>(_shader)->gpuShaderObject()->wgpuShaderFragmentModule,
|
||||
.entryPoint = "main",
|
||||
.targetCount = colorTargetStates.size(),
|
||||
.targets = colorTargetStates.data(),
|
||||
};
|
||||
|
||||
// pipelineLayout->prepare(setInUse);
|
||||
|
||||
WGPURenderPipelineDescriptor piplineDesc = {
|
||||
.nextInChain = nullptr,
|
||||
.label = static_cast<CCWGPUShader *>(_shader)->getName().c_str(),
|
||||
.layout = pipelineLayout->gpuPipelineLayoutObject()->wgpuPipelineLayout,
|
||||
.vertex = vertexState,
|
||||
.primitive = primitiveState,
|
||||
.depthStencil = dsState.format == WGPUTextureFormat_Undefined ? nullptr : &dsState,
|
||||
.multisample = msState,
|
||||
.fragment = &fragmentState,
|
||||
};
|
||||
|
||||
auto hashVal = hash(piplineDesc);
|
||||
_hash = hashVal;
|
||||
|
||||
auto iter = pipelineMap.find(hashVal);
|
||||
if (iter == pipelineMap.end()) {
|
||||
_gpuPipelineStateObj->wgpuRenderPipeline = wgpuDeviceCreateRenderPipeline(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &piplineDesc);
|
||||
printf("ppl %s\n", static_cast<CCWGPUShader *>(_shader)->getName().c_str());
|
||||
pipelineMap[hashVal] = _gpuPipelineStateObj->wgpuRenderPipeline;
|
||||
} else {
|
||||
_gpuPipelineStateObj->wgpuRenderPipeline = static_cast<WGPURenderPipeline>(iter->second);
|
||||
}
|
||||
_ppl = pipelineLayout;
|
||||
_forceUpdate = false;
|
||||
} else if (_bindPoint == PipelineBindPoint::COMPUTE) {
|
||||
if (_gpuPipelineStateObj->wgpuComputePipeline && !_forceUpdate)
|
||||
return;
|
||||
WGPUProgrammableStageDescriptor psDesc = {
|
||||
.module = static_cast<CCWGPUShader *>(_shader)->gpuShaderObject()->wgpuShaderComputeModule,
|
||||
.entryPoint = "main",
|
||||
};
|
||||
// pipelineLayout->prepare(setInUse);
|
||||
WGPUComputePipelineDescriptor piplineDesc = {
|
||||
.layout = pipelineLayout->gpuPipelineLayoutObject()->wgpuPipelineLayout,
|
||||
.compute = psDesc,
|
||||
};
|
||||
auto hashVal = hash(piplineDesc);
|
||||
_hash = hashVal;
|
||||
|
||||
auto iter = pipelineMap.find(hashVal);
|
||||
if (iter == pipelineMap.end()) {
|
||||
_gpuPipelineStateObj->wgpuComputePipeline = wgpuDeviceCreateComputePipeline(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &piplineDesc);
|
||||
printf("ppl %s\n", static_cast<CCWGPUShader *>(_shader)->getName().c_str());
|
||||
pipelineMap[hashVal] = _gpuPipelineStateObj->wgpuComputePipeline;
|
||||
} else {
|
||||
_gpuPipelineStateObj->wgpuComputePipeline = static_cast<WGPUComputePipeline>(iter->second);
|
||||
}
|
||||
_ppl = pipelineLayout;
|
||||
_forceUpdate = false;
|
||||
} else {
|
||||
printf("unsupport pipeline bind point");
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUPipelineState::doDestroy() {
|
||||
if (_gpuPipelineStateObj) {
|
||||
if (_gpuPipelineStateObj->wgpuRenderPipeline) {
|
||||
wgpuRenderPipelineRelease(_gpuPipelineStateObj->wgpuRenderPipeline);
|
||||
}
|
||||
if (_gpuPipelineStateObj->wgpuComputePipeline) {
|
||||
wgpuComputePipelineRelease(_gpuPipelineStateObj->wgpuComputePipeline);
|
||||
}
|
||||
|
||||
delete _gpuPipelineStateObj;
|
||||
_gpuPipelineStateObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
67
cocos/renderer/gfx-wgpu/WGPUPipelineState.h
Normal file
67
cocos/renderer/gfx-wgpu/WGPUPipelineState.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "base/std/container/map.h"
|
||||
#include "base/std/container/set.h"
|
||||
#include "gfx-base/GFXPipelineState.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUPipelineStateObject;
|
||||
|
||||
class CCWGPUPipelineState final : public PipelineState {
|
||||
public:
|
||||
CCWGPUPipelineState();
|
||||
~CCWGPUPipelineState();
|
||||
|
||||
inline CCWGPUPipelineStateObject *gpuPipelineStateObject() { return _gpuPipelineStateObj; }
|
||||
|
||||
void check(RenderPass *renderPass, bool forceUpdate = false);
|
||||
void prepare(const ccstd::set<uint8_t> &setInUse);
|
||||
PipelineLayout *layout() const { return _pipelineLayout; }
|
||||
|
||||
void *ppl() const { return _ppl; }
|
||||
|
||||
static ccstd::map<ccstd::hash_t, void *> pipelineMap;
|
||||
|
||||
inline ccstd::hash_t getHash() const { return _hash; }
|
||||
|
||||
protected:
|
||||
void doInit(const PipelineStateInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUPipelineStateObject *_gpuPipelineStateObj = nullptr;
|
||||
|
||||
void *_ppl = nullptr;
|
||||
bool _forceUpdate = false;
|
||||
ccstd::hash_t _hash{0};
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
62
cocos/renderer/gfx-wgpu/WGPUQueryPool.cpp
Normal file
62
cocos/renderer/gfx-wgpu/WGPUQueryPool.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
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 "WGPUQueryPool.h"
|
||||
#include "WGPUCommandBuffer.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
CCWGPUQueryPool::CCWGPUQueryPool() {
|
||||
_typedID = generateObjectID<decltype(this)>();
|
||||
}
|
||||
|
||||
CCWGPUQueryPool::~CCWGPUQueryPool() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUQueryPool::doInit(const QueryPoolInfo & /*info*/) {
|
||||
CCWGPUDevice *device = CCWGPUDevice::getInstance();
|
||||
_gpuQueryPool = ccnew CCWGPUQueryPoolObject;
|
||||
_gpuQueryPool->type = _type;
|
||||
_gpuQueryPool->maxQueryObjects = _maxQueryObjects;
|
||||
_gpuQueryPool->idPool.resize(_maxQueryObjects, 0U);
|
||||
|
||||
// TODO_Zeqiang: wgpu query
|
||||
|
||||
// cmdFuncGLES3CreateQuery(device, _gpuQueryPool);
|
||||
}
|
||||
|
||||
void CCWGPUQueryPool::doDestroy() {
|
||||
if (_gpuQueryPool) {
|
||||
// cmdFuncGLES3DestroyQuery(GLES3Device::getInstance(), _gpuQueryPool);
|
||||
delete _gpuQueryPool;
|
||||
_gpuQueryPool = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
57
cocos/renderer/gfx-wgpu/WGPUQueryPool.h
Normal file
57
cocos/renderer/gfx-wgpu/WGPUQueryPool.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
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/std/container/vector.h"
|
||||
#include "gfx-base/GFXQueryPool.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CCWGPUQueryPoolObject;
|
||||
|
||||
class CCWGPUQueryPool final : public QueryPool {
|
||||
public:
|
||||
CCWGPUQueryPool();
|
||||
~CCWGPUQueryPool() override;
|
||||
|
||||
inline CCWGPUQueryPoolObject *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:
|
||||
void doInit(const QueryPoolInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUQueryPoolObject *_gpuQueryPool = nullptr;
|
||||
ccstd::vector<uint32_t> _ids;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
111
cocos/renderer/gfx-wgpu/WGPUQueue.cpp
Normal file
111
cocos/renderer/gfx-wgpu/WGPUQueue.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUQueue.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include "WGPUCommandBuffer.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUUtils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
CCWGPUQueue::CCWGPUQueue() : Queue() {
|
||||
}
|
||||
|
||||
CCWGPUQueue::~CCWGPUQueue() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUQueue::doInit(const QueueInfo &info) {
|
||||
_gpuQueueObject = ccnew CCWGPUQueueObject;
|
||||
_gpuQueueObject->type = info.type;
|
||||
_gpuQueueObject->wgpuQueue = wgpuDeviceGetQueue(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice);
|
||||
}
|
||||
|
||||
void CCWGPUQueue::doDestroy() {
|
||||
if (_gpuQueueObject) {
|
||||
if (_gpuQueueObject->wgpuQueue) {
|
||||
wgpuQueueRelease(_gpuQueueObject->wgpuQueue);
|
||||
}
|
||||
delete _gpuQueueObject;
|
||||
_gpuQueueObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void wgpuQueueSubmitCallback(WGPUQueueWorkDoneStatus status, void *userdata) {
|
||||
auto *recycleBin = static_cast<CCWGPURecycleBin *>(userdata);
|
||||
recycleBin->bufferBin.purge();
|
||||
recycleBin->textureBin.purge();
|
||||
recycleBin->queryBin.purge();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void CCWGPUQueue::submit(CommandBuffer *const *cmdBuffs, uint32_t count) {
|
||||
// ccstd::vector<WGPUCommandBuffer> commandBuffs(count);
|
||||
// for (size_t i = 0; i < count; i++) {
|
||||
// auto* commandBuff = static_cast<CCWGPUCommandBuffer*>(cmdBuffs[i]);
|
||||
// commandBuffs[i] = commandBuff->gpuCommandBufferObject()->wgpuCommandBuffer;
|
||||
// }
|
||||
// wgpuQueueSubmit(_gpuQueueObject->wgpuQueue, count, commandBuffs.data());
|
||||
// for (size_t i = 0; i < count; i++) {
|
||||
// auto* commandBuff = static_cast<CCWGPUCommandBuffer*>(cmdBuffs[i]);
|
||||
// wgpuCommandBufferRelease(commandBuff->gpuCommandBufferObject()->wgpuCommandBuffer);
|
||||
// }
|
||||
|
||||
// CCWGPUDevice::getInstance()->stagingBuffer()->unmap();
|
||||
|
||||
ccstd::vector<WGPUCommandBuffer> wgpuCmdBuffs(count);
|
||||
ccstd::vector<WGPUCommandEncoder> wgpuCmdEncoders(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const auto *cmdBuff = static_cast<CCWGPUCommandBuffer *>(cmdBuffs[i]);
|
||||
wgpuCmdBuffs[i] = cmdBuff->gpuCommandBufferObject()->wgpuCommandBuffer;
|
||||
wgpuCmdEncoders[i] = cmdBuff->gpuCommandBufferObject()->wgpuCommandEncoder;
|
||||
|
||||
_numDrawCalls += cmdBuff->getNumDrawCalls();
|
||||
_numInstances += cmdBuff->getNumInstances();
|
||||
_numTriangles += cmdBuff->getNumTris();
|
||||
|
||||
const_cast<CCWGPUCommandBuffer*>(cmdBuff)->reset();
|
||||
}
|
||||
|
||||
wgpuQueueSubmit(_gpuQueueObject->wgpuQueue, count, wgpuCmdBuffs.data());
|
||||
std::for_each(wgpuCmdBuffs.begin(), wgpuCmdBuffs.end(), [](auto wgpuCmdBuffer) {
|
||||
wgpuCommandBufferRelease(wgpuCmdBuffer);
|
||||
});
|
||||
std::for_each(wgpuCmdEncoders.begin(), wgpuCmdEncoders.end(), [](auto wgpuCmdEncoder) {
|
||||
wgpuCommandEncoderRelease(wgpuCmdEncoder);
|
||||
});
|
||||
|
||||
auto *recycleBin = CCWGPUDevice::getInstance()->recycleBin();
|
||||
wgpuQueueOnSubmittedWorkDone(_gpuQueueObject->wgpuQueue, 0, wgpuQueueSubmitCallback, recycleBin);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
62
cocos/renderer/gfx-wgpu/WGPUQueue.h
Normal file
62
cocos/renderer/gfx-wgpu/WGPUQueue.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "gfx-base/GFXQueue.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUQueueObject;
|
||||
|
||||
class CCWGPUQueue final : public Queue {
|
||||
public:
|
||||
CCWGPUQueue();
|
||||
~CCWGPUQueue();
|
||||
|
||||
void submit(CommandBuffer *const *cmdBuffs, uint32_t count) override;
|
||||
inline CCWGPUQueueObject *gpuQueueObject() { return _gpuQueueObject; }
|
||||
inline uint32_t getNumDrawCalls() const { return _numDrawCalls; }
|
||||
inline uint32_t getNumInstances() const { return _numInstances; }
|
||||
inline uint32_t getNumTris() const { return _numTriangles; }
|
||||
|
||||
inline void resetStatus() { _numDrawCalls = _numInstances = _numTriangles = 0; }
|
||||
|
||||
protected:
|
||||
void doInit(const QueueInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUQueueObject *_gpuQueueObject = nullptr;
|
||||
|
||||
uint32_t _numDrawCalls = 0;
|
||||
uint32_t _numInstances = 0;
|
||||
uint32_t _numTriangles = 0;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
109
cocos/renderer/gfx-wgpu/WGPURenderPass.cpp
Normal file
109
cocos/renderer/gfx-wgpu/WGPURenderPass.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPURenderPass.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUUtils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
class CCWGPURenderPassHelper {
|
||||
public:
|
||||
explicit CCWGPURenderPassHelper(const RenderPassInfo &info) {
|
||||
SampleCount samples = SampleCount::X1;
|
||||
for (size_t i = 0; i < info.colorAttachments.size(); i++) {
|
||||
colors[i].loadOp = toWGPULoadOp(info.colorAttachments[i].loadOp);
|
||||
colors[i].storeOp = toWGPUStoreOp(info.colorAttachments[i].storeOp);
|
||||
colors[i].clearValue = defaultClearColor;
|
||||
// TODO_Zeqaing : subpass
|
||||
if (info.colorAttachments[i].sampleCount != SampleCount::X1)
|
||||
samples = info.colorAttachments[i].sampleCount;
|
||||
}
|
||||
|
||||
// now 1 depth stencil only
|
||||
depthStencils[0].depthLoadOp = toWGPULoadOp(info.depthStencilAttachment.depthLoadOp);
|
||||
depthStencils[0].depthStoreOp = toWGPUStoreOp(info.depthStencilAttachment.depthStoreOp);
|
||||
depthStencils[0].stencilLoadOp = toWGPULoadOp(info.depthStencilAttachment.stencilLoadOp);
|
||||
depthStencils[0].stencilStoreOp = toWGPUStoreOp(info.depthStencilAttachment.stencilStoreOp);
|
||||
depthStencils[0].depthClearValue = defaultClearDepth;
|
||||
depthStencils[0].depthReadOnly = false;
|
||||
depthStencils[0].stencilReadOnly = false;
|
||||
if (samples == SampleCount::X1)
|
||||
samples = info.depthStencilAttachment.sampleCount;
|
||||
|
||||
renderPassDesc = ccnew WGPURenderPassDescriptor;
|
||||
|
||||
// TODO_Zeqiang: Metal-like subpass
|
||||
renderPassDesc->colorAttachmentCount = info.colorAttachments.size();
|
||||
renderPassDesc->colorAttachments = colors.data();
|
||||
renderPassDesc->depthStencilAttachment = depthStencils.data();
|
||||
|
||||
sampleCount = toWGPUSampleCount(samples);
|
||||
}
|
||||
|
||||
~CCWGPURenderPassHelper() {
|
||||
if (renderPassDesc) {
|
||||
delete renderPassDesc;
|
||||
renderPassDesc = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::array<WGPURenderPassColorAttachment, CC_WGPU_MAX_ATTACHMENTS> colors;
|
||||
ccstd::array<WGPURenderPassDepthStencilAttachment, CC_WGPU_MAX_ATTACHMENTS> depthStencils;
|
||||
WGPURenderPassDescriptor *renderPassDesc = nullptr;
|
||||
int sampleCount = 1;
|
||||
};
|
||||
|
||||
CCWGPURenderPass::CCWGPURenderPass() : RenderPass() {
|
||||
}
|
||||
|
||||
CCWGPURenderPass::~CCWGPURenderPass() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPURenderPass::doInit(const RenderPassInfo &info) {
|
||||
_renderPassObject = ccnew CCWGPURenderPassObject();
|
||||
_rpHelper = ccnew CCWGPURenderPassHelper(info);
|
||||
_renderPassObject->wgpuRenderPassDesc = _rpHelper->renderPassDesc;
|
||||
_renderPassObject->sampleCount = _rpHelper->sampleCount;
|
||||
}
|
||||
|
||||
void CCWGPURenderPass::doDestroy() {
|
||||
if (_renderPassObject) {
|
||||
delete _renderPassObject;
|
||||
_renderPassObject = nullptr;
|
||||
}
|
||||
if (_rpHelper) {
|
||||
delete _rpHelper;
|
||||
_rpHelper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
60
cocos/renderer/gfx-wgpu/WGPURenderPass.h
Normal file
60
cocos/renderer/gfx-wgpu/WGPURenderPass.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "gfx-base/GFXRenderPass.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPURenderPassObject;
|
||||
class CCWGPURenderPassHelper;
|
||||
|
||||
class CCWGPURenderPass final : public RenderPass {
|
||||
public:
|
||||
CCWGPURenderPass();
|
||||
~CCWGPURenderPass();
|
||||
|
||||
inline CCWGPURenderPassObject *gpuRenderPassObject() { return _renderPassObject; }
|
||||
|
||||
using RenderPass::initialize;
|
||||
|
||||
protected:
|
||||
void doInit(const RenderPassInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPURenderPassObject *_renderPassObject = nullptr;
|
||||
CCWGPURenderPassHelper *_rpHelper = nullptr;
|
||||
};
|
||||
|
||||
inline CCWGPURenderPass *getThis(CCWGPURenderPass *that) {
|
||||
return that;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
101
cocos/renderer/gfx-wgpu/WGPUSampler.cpp
Normal file
101
cocos/renderer/gfx-wgpu/WGPUSampler.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUSampler.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include <limits>
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUUtils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
CCWGPUSampler *dftFilterableSampler = nullptr;
|
||||
CCWGPUSampler *dftUnfilterableSampler = nullptr;
|
||||
} // namespace
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
CCWGPUSampler::CCWGPUSampler(const SamplerInfo &info) : Sampler(info) {
|
||||
ccstd::string tag = std::to_string(static_cast<uint32_t>(info.minFilter)) + " " + std::to_string(static_cast<uint32_t>(info.magFilter)) + " " + std::to_string(static_cast<uint32_t>(info.mipFilter));
|
||||
WGPUSamplerDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = tag.c_str(),
|
||||
.addressModeU = toWGPUAddressMode(info.addressU),
|
||||
.addressModeV = toWGPUAddressMode(info.addressV),
|
||||
.addressModeW = toWGPUAddressMode(info.addressW),
|
||||
.magFilter = toWGPUFilterMode(info.magFilter),
|
||||
.minFilter = toWGPUFilterMode(info.minFilter),
|
||||
.mipmapFilter = toWGPUMipmapFilterMode(info.mipFilter),
|
||||
.lodMinClamp = 0.0f,
|
||||
.lodMaxClamp = std::numeric_limits<float>::max(),
|
||||
.compare = WGPUCompareFunction_Undefined, // toWGPUCompareFunction(info.cmpFunc),
|
||||
.maxAnisotropy = static_cast<uint16_t>(info.maxAnisotropy),
|
||||
};
|
||||
|
||||
auto *device = CCWGPUDevice::getInstance();
|
||||
_wgpuSampler = wgpuDeviceCreateSampler(device->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
}
|
||||
|
||||
CCWGPUSampler::~CCWGPUSampler() {
|
||||
wgpuSamplerRelease(_wgpuSampler);
|
||||
}
|
||||
|
||||
CCWGPUSampler *CCWGPUSampler::defaultFilterableSampler() {
|
||||
if (!dftFilterableSampler) {
|
||||
SamplerInfo info = {
|
||||
.minFilter = Filter::LINEAR,
|
||||
.magFilter = Filter::LINEAR,
|
||||
.mipFilter = Filter::LINEAR,
|
||||
.addressU = Address::WRAP,
|
||||
.addressV = Address::WRAP,
|
||||
.addressW = Address::WRAP,
|
||||
.maxAnisotropy = 0,
|
||||
.cmpFunc = ComparisonFunc::ALWAYS,
|
||||
};
|
||||
dftFilterableSampler = ccnew CCWGPUSampler(info);
|
||||
}
|
||||
return dftFilterableSampler;
|
||||
}
|
||||
|
||||
CCWGPUSampler *CCWGPUSampler::defaultUnfilterableSampler() {
|
||||
if (!dftUnfilterableSampler) {
|
||||
SamplerInfo info = {
|
||||
.minFilter = Filter::POINT,
|
||||
.magFilter = Filter::POINT,
|
||||
.mipFilter = Filter::POINT,
|
||||
.addressU = Address::WRAP,
|
||||
.addressV = Address::WRAP,
|
||||
.addressW = Address::WRAP,
|
||||
.maxAnisotropy = 0,
|
||||
.cmpFunc = ComparisonFunc::ALWAYS,
|
||||
};
|
||||
dftUnfilterableSampler = ccnew CCWGPUSampler(info);
|
||||
}
|
||||
return dftUnfilterableSampler;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
55
cocos/renderer/gfx-wgpu/WGPUSampler.h
Normal file
55
cocos/renderer/gfx-wgpu/WGPUSampler.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "gfx-base/states/GFXSampler.h"
|
||||
|
||||
#include "WGPUObject.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CCWGPUSampler final : public Sampler {
|
||||
public:
|
||||
explicit CCWGPUSampler(const SamplerInfo &info);
|
||||
~CCWGPUSampler();
|
||||
|
||||
inline WGPUSampler gpuSampler() const { return _wgpuSampler; }
|
||||
|
||||
static CCWGPUSampler *defaultFilterableSampler();
|
||||
static CCWGPUSampler *defaultUnfilterableSampler();
|
||||
|
||||
// stamp current state
|
||||
void stamp() {}
|
||||
bool internalChanged() const { return false; }
|
||||
|
||||
protected:
|
||||
WGPUSampler _wgpuSampler = wgpuDefaultHandle;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
234
cocos/renderer/gfx-wgpu/WGPUShader.cpp
Normal file
234
cocos/renderer/gfx-wgpu/WGPUShader.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUShader.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUUtils.h"
|
||||
#include "gfx-base/GFXDef-common.h"
|
||||
#define USE_NATIVE_SPIRV 0
|
||||
#if USE_NATIVE_SPIRV
|
||||
#include "gfx-base/SPIRVUtils.h"
|
||||
#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
#define SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
|
||||
#endif
|
||||
#include "spirv_cross/spirv_msl.hpp"
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
using namespace emscripten;
|
||||
SPIRVUtils *CCWGPUShader::spirv = nullptr;
|
||||
|
||||
CCWGPUShader::CCWGPUShader() : Shader() {
|
||||
}
|
||||
|
||||
CCWGPUShader::~CCWGPUShader() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUShader::initialize(const ShaderInfo &info, const std::vector<std::vector<uint32_t>> &spirvs) {
|
||||
_gpuShaderObject = ccnew CCWGPUShaderObject;
|
||||
|
||||
_name = info.name;
|
||||
_stages = info.stages;
|
||||
_attributes = info.attributes;
|
||||
_blocks = info.blocks;
|
||||
_buffers = info.buffers;
|
||||
_samplerTextures = info.samplerTextures;
|
||||
_samplers = info.samplers;
|
||||
_textures = info.textures;
|
||||
_images = info.images;
|
||||
_subpassInputs = info.subpassInputs;
|
||||
|
||||
_gpuShaderObject->name = info.name;
|
||||
for (size_t i = 0; i < info.stages.size(); i++) {
|
||||
const auto &stage = info.stages[i];
|
||||
auto *spvData = spirvs[i].data();
|
||||
size_t size = spirvs[i].size();
|
||||
|
||||
WGPUShaderModuleSPIRVDescriptor spv = {};
|
||||
spv.chain.sType = WGPUSType_ShaderModuleSPIRVDescriptor;
|
||||
spv.codeSize = size;
|
||||
spv.code = spvData;
|
||||
WGPUShaderModuleDescriptor desc = {};
|
||||
desc.nextInChain = reinterpret_cast<WGPUChainedStruct *>(&spv);
|
||||
desc.label = _name.c_str();
|
||||
if (stage.stage == ShaderStageFlagBit::VERTEX) {
|
||||
_gpuShaderObject->wgpuShaderVertexModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else if (stage.stage == ShaderStageFlagBit::FRAGMENT) {
|
||||
_gpuShaderObject->wgpuShaderFragmentModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else if (stage.stage == ShaderStageFlagBit::COMPUTE) {
|
||||
_gpuShaderObject->wgpuShaderComputeModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else {
|
||||
printf("unsupport shader stage.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUShader::initWithWGSL(const ShaderInfo& info) {
|
||||
_gpuShaderObject = ccnew CCWGPUShaderObject;
|
||||
|
||||
_name = info.name;
|
||||
_stages = info.stages;
|
||||
_attributes = info.attributes;
|
||||
_blocks = info.blocks;
|
||||
_buffers = info.buffers;
|
||||
_samplerTextures = info.samplerTextures;
|
||||
_samplers = info.samplers;
|
||||
_textures = info.textures;
|
||||
_images = info.images;
|
||||
_subpassInputs = info.subpassInputs;
|
||||
|
||||
_gpuShaderObject->name = info.name;
|
||||
for (size_t i = 0; i < info.stages.size(); i++) {
|
||||
const auto &stage = info.stages[i];
|
||||
WGPUShaderModuleWGSLDescriptor wgslDesc = {};
|
||||
wgslDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
||||
wgslDesc.code = stage.source.c_str();
|
||||
WGPUShaderModuleDescriptor desc = {};
|
||||
desc.nextInChain = reinterpret_cast<WGPUChainedStruct *>(&wgslDesc);
|
||||
desc.label = _name.c_str();
|
||||
if (stage.stage == ShaderStageFlagBit::VERTEX) {
|
||||
_gpuShaderObject->wgpuShaderVertexModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else if (stage.stage == ShaderStageFlagBit::FRAGMENT) {
|
||||
_gpuShaderObject->wgpuShaderFragmentModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else if (stage.stage == ShaderStageFlagBit::COMPUTE) {
|
||||
_gpuShaderObject->wgpuShaderComputeModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else {
|
||||
printf("unsupport shader stage.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string spirvProcess(const uint32_t *data, size_t size, const UniformSamplerTextureList &list) {
|
||||
#if USE_NATIVE_SPIRV
|
||||
spirv_cross::CompilerMSL compiler(data, size);
|
||||
auto executionModel = compiler.get_execution_model();
|
||||
|
||||
auto active = compiler.get_active_interface_variables();
|
||||
spirv_cross::ShaderResources resources = compiler.get_shader_resources(active);
|
||||
compiler.set_enabled_interface_variables(std::move(active));
|
||||
|
||||
// Set some options.
|
||||
spirv_cross::CompilerMSL::Options options;
|
||||
options.enable_decoration_binding = true;
|
||||
options.set_msl_version(2, 3, 0);
|
||||
compiler.set_msl_options(options);
|
||||
|
||||
printf("size should be eq %d ,%d\n", list.size(), resources.sampled_images.size());
|
||||
|
||||
for (size_t i = 0; i < resources.sampled_images.size(); ++i) {
|
||||
const auto &sampler = resources.sampled_images[i];
|
||||
auto set = compiler.get_decoration(sampler.id, spv::DecorationDescriptorSet);
|
||||
auto binding = compiler.get_decoration(sampler.id, spv::DecorationBinding);
|
||||
int size = 1;
|
||||
// const spirv_cross::SPIRType &type = msl.get_type(sampler.type_id);
|
||||
// if (type.array_size_literal[0]) {
|
||||
// size = type.array[0];
|
||||
// }
|
||||
|
||||
// for (int i = 0; i < size; ++i) {
|
||||
spirv_cross::MSLResourceBinding newBinding;
|
||||
newBinding.stage = executionModel;
|
||||
newBinding.desc_set = set;
|
||||
newBinding.binding = list[i].binding;
|
||||
newBinding.msl_texture = binding;
|
||||
newBinding.msl_sampler = binding + 16;
|
||||
compiler.add_msl_resource_binding(newBinding);
|
||||
|
||||
// if (gpuShader->samplers.find(mappedBinding) == gpuShader->samplers.end()) {
|
||||
// gpuShader->samplers[mappedBinding] = {sampler.name, set, binding, newBinding.msl_texture, newBinding.msl_sampler, shaderType};
|
||||
// } else {
|
||||
// gpuShader->samplers[mappedBinding].stages |= shaderType;
|
||||
// }
|
||||
// ++gpuShader->samplerIndex;
|
||||
// }
|
||||
}
|
||||
|
||||
const std::string &msl = compiler.compile();
|
||||
return msl;
|
||||
#else
|
||||
return std::string{};
|
||||
#endif
|
||||
}
|
||||
|
||||
void CCWGPUShader::doInit(const ShaderInfo &info) {
|
||||
initWithWGSL(info);
|
||||
#if USE_NATIVE_SPIRV
|
||||
_gpuShaderObject = ccnew CCWGPUShaderObject;
|
||||
if (!spirv) {
|
||||
spirv = SPIRVUtils::getInstance();
|
||||
spirv->initialize(1);
|
||||
}
|
||||
_gpuShaderObject->name = info.name;
|
||||
for (auto &stage : info.stages) {
|
||||
spirv->compileGLSL(stage.stage, "#version 450\n" + stage.source);
|
||||
// const auto &data = spirv->getOutputData();
|
||||
|
||||
std::string glsl = spirvProcess(spirv->getOutputData(), spirv->getOutputSize() / sizeof(uint32_t), _samplerTextures);
|
||||
spirv->compileGLSL(stage.stage, glsl);
|
||||
auto *spvData = spirv->getOutputData();
|
||||
size_t size = spirv->getOutputSize() / sizeof(uint32_t);
|
||||
|
||||
WGPUShaderModuleSPIRVDescriptor spv = {};
|
||||
spv.chain.sType = WGPUSType_ShaderModuleSPIRVDescriptor;
|
||||
spv.codeSize = size;
|
||||
spv.code = spvData;
|
||||
WGPUShaderModuleDescriptor desc = {};
|
||||
desc.nextInChain = reinterpret_cast<WGPUChainedStruct *>(&spv);
|
||||
desc.label = nullptr;
|
||||
if (stage.stage == ShaderStageFlagBit::VERTEX) {
|
||||
_gpuShaderObject->wgpuShaderVertexModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else if (stage.stage == ShaderStageFlagBit::FRAGMENT) {
|
||||
_gpuShaderObject->wgpuShaderFragmentModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else if (stage.stage == ShaderStageFlagBit::COMPUTE) {
|
||||
_gpuShaderObject->wgpuShaderComputeModule = wgpuDeviceCreateShaderModule(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &desc);
|
||||
} else {
|
||||
printf("unsupport shader stage.");
|
||||
}
|
||||
}
|
||||
// printf("sahdername: %s\n", info.name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void CCWGPUShader::doDestroy() {
|
||||
if (_gpuShaderObject) {
|
||||
if (_gpuShaderObject->wgpuShaderVertexModule) {
|
||||
wgpuShaderModuleRelease(_gpuShaderObject->wgpuShaderVertexModule);
|
||||
}
|
||||
if (_gpuShaderObject->wgpuShaderFragmentModule) {
|
||||
wgpuShaderModuleRelease(_gpuShaderObject->wgpuShaderFragmentModule);
|
||||
}
|
||||
if (_gpuShaderObject->wgpuShaderComputeModule) {
|
||||
wgpuShaderModuleRelease(_gpuShaderObject->wgpuShaderComputeModule);
|
||||
}
|
||||
delete _gpuShaderObject;
|
||||
_gpuShaderObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
65
cocos/renderer/gfx-wgpu/WGPUShader.h
Normal file
65
cocos/renderer/gfx-wgpu/WGPUShader.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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-base/GFXDef-common.h"
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "gfx-base/GFXShader.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUShaderObject;
|
||||
class SPIRVUtils;
|
||||
|
||||
class CCWGPUShader final : public Shader {
|
||||
public:
|
||||
CCWGPUShader();
|
||||
~CCWGPUShader();
|
||||
|
||||
inline CCWGPUShaderObject *gpuShaderObject() { return _gpuShaderObject; }
|
||||
|
||||
void initialize(const ShaderInfo &info) { doInit(info); }
|
||||
|
||||
// ems export
|
||||
EXPORT_EMS(
|
||||
void initialize(const ShaderInfo &info, emscripten::val &spirvs);
|
||||
void reflectBinding(const emscripten::val& bindings);
|
||||
)
|
||||
|
||||
void initialize(const ShaderInfo &info, const std::vector<std::vector<uint32_t>> &spirvs);
|
||||
void initWithWGSL(const ShaderInfo& info);
|
||||
|
||||
protected:
|
||||
void doInit(const ShaderInfo &info) override;
|
||||
void doDestroy() override;
|
||||
|
||||
CCWGPUShaderObject *_gpuShaderObject = nullptr;
|
||||
static SPIRVUtils *spirv;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
143
cocos/renderer/gfx-wgpu/WGPUSwapchain.cpp
Normal file
143
cocos/renderer/gfx-wgpu/WGPUSwapchain.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUSwapchain.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUTexture.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
CCWGPUSwapchain::CCWGPUSwapchain(CCWGPUDevice *device) {
|
||||
_device = device;
|
||||
}
|
||||
|
||||
CCWGPUSwapchain::~CCWGPUSwapchain() {
|
||||
_device = nullptr;
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUSwapchain::doInit(const SwapchainInfo &info) {
|
||||
printf("swapchain init %d, %d\n", info.width, info.height);
|
||||
// WGPUSurfaceDescriptorFromCanvasHTMLSelector canvDesc = {};
|
||||
// canvDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
|
||||
// canvDesc.selector = "canvas";
|
||||
|
||||
// WGPUSurfaceDescriptor surfDesc = {};
|
||||
// surfDesc.nextInChain = reinterpret_cast<WGPUChainedStruct *>(&canvDesc);
|
||||
// WGPUSurface surface = wgpuInstanceCreateSurface(nullptr, &surfDesc);
|
||||
|
||||
auto *device = CCWGPUDevice::getInstance();
|
||||
CCWGPUDeviceObject *gpuDeviceObj = device->gpuDeviceObject();
|
||||
auto surface = gpuDeviceObj->instance.wgpuSurface;
|
||||
WGPUPresentMode presentMode;
|
||||
switch (info.vsyncMode) {
|
||||
case VsyncMode::OFF:
|
||||
presentMode = WGPUPresentMode_Immediate;
|
||||
break;
|
||||
case VsyncMode::ON:
|
||||
presentMode = WGPUPresentMode_Fifo;
|
||||
break;
|
||||
case VsyncMode::RELAXED:
|
||||
presentMode = WGPUPresentMode_Fifo;
|
||||
break;
|
||||
case VsyncMode::MAILBOX:
|
||||
presentMode = WGPUPresentMode_Mailbox;
|
||||
break;
|
||||
case VsyncMode::HALF:
|
||||
presentMode = WGPUPresentMode_Force32;
|
||||
break;
|
||||
default:
|
||||
presentMode = WGPUPresentMode_Fifo;
|
||||
}
|
||||
|
||||
WGPUSwapChainDescriptor swapChainDesc;
|
||||
swapChainDesc.nextInChain = nullptr;
|
||||
swapChainDesc.label = "defaultSwapChain";
|
||||
swapChainDesc.usage = WGPUTextureUsage_RenderAttachment;
|
||||
swapChainDesc.format = WGPUTextureFormat_BGRA8Unorm;
|
||||
swapChainDesc.width = info.width;
|
||||
swapChainDesc.height = info.height;
|
||||
swapChainDesc.presentMode = presentMode;
|
||||
|
||||
WGPUSwapChain swapChain = wgpuDeviceCreateSwapChain(gpuDeviceObj->wgpuDevice, surface, &swapChainDesc);
|
||||
_gpuSwapchainObj = ccnew CCWGPUSwapchainObject;
|
||||
_gpuSwapchainObj->wgpuSwapChain = swapChain;
|
||||
_gpuSwapchainObj->wgpuSurface = surface;
|
||||
|
||||
SwapchainTextureInfo textureInfo = {
|
||||
.swapchain = this,
|
||||
.format = Format::BGRA8,
|
||||
.width = info.width,
|
||||
.height = info.height,
|
||||
};
|
||||
|
||||
printf("swapchain init %d, %d\n", info.width, info.height);
|
||||
|
||||
printf("swapchain tex init %d, %d\n", textureInfo.width, textureInfo.height);
|
||||
|
||||
_colorTexture = _gpuSwapchainObj->swapchainColor = ccnew CCWGPUTexture;
|
||||
initTexture(textureInfo, _gpuSwapchainObj->swapchainColor);
|
||||
textureInfo.format = Format::DEPTH_STENCIL;
|
||||
_depthStencilTexture = _gpuSwapchainObj->swapchainDepthStencil = ccnew CCWGPUTexture;
|
||||
initTexture(textureInfo, _gpuSwapchainObj->swapchainDepthStencil);
|
||||
|
||||
// TODO: wgpuInstance
|
||||
|
||||
device->registerSwapchain(this);
|
||||
}
|
||||
|
||||
void CCWGPUSwapchain::doDestroy() {
|
||||
wgpuSwapChainRelease(_gpuSwapchainObj->wgpuSwapChain);
|
||||
|
||||
CCWGPUDevice::getInstance()->unRegisterSwapchain(this);
|
||||
|
||||
if (_gpuSwapchainObj) {
|
||||
delete _gpuSwapchainObj->swapchainColor;
|
||||
delete _gpuSwapchainObj->swapchainDepthStencil;
|
||||
delete _gpuSwapchainObj;
|
||||
_gpuSwapchainObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CCWGPUSwapchain::doResize(uint32_t width, uint32_t height, SurfaceTransform transform) {
|
||||
_colorTexture->resize(width, height);
|
||||
_depthStencilTexture->resize(width, height);
|
||||
}
|
||||
|
||||
void CCWGPUSwapchain::update() {
|
||||
auto swapchainView = static_cast<CCWGPUTexture *>(_colorTexture.get())->gpuTextureObject()->selfView;
|
||||
wgpuTextureViewRelease(swapchainView);
|
||||
static_cast<CCWGPUTexture *>(_colorTexture.get())->gpuTextureObject()->selfView = wgpuSwapChainGetCurrentTextureView(_gpuSwapchainObj->wgpuSwapChain);
|
||||
}
|
||||
|
||||
void CCWGPUSwapchain::doDestroySurface() {
|
||||
}
|
||||
|
||||
void CCWGPUSwapchain::doCreateSurface(void *windowHandle) {
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
63
cocos/renderer/gfx-wgpu/WGPUSwapchain.h
Normal file
63
cocos/renderer/gfx-wgpu/WGPUSwapchain.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUDef.h"
|
||||
#include "gfx-base/GFXSwapchain.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace gfx {
|
||||
struct CCWGPUSwapchainObject;
|
||||
|
||||
class CCWGPUTexture;
|
||||
class CCWGPUDevice;
|
||||
class CCWGPUSwapchain final : public Swapchain {
|
||||
public:
|
||||
CCWGPUSwapchain(CCWGPUDevice *device);
|
||||
~CCWGPUSwapchain();
|
||||
|
||||
inline CCWGPUSwapchainObject *gpuSwapchainObject() { return _gpuSwapchainObj; }
|
||||
|
||||
inline void setColorTexture(Texture *tex) { _colorTexture = tex; }
|
||||
inline void setDepthStencilTexture(Texture *tex) { _depthStencilTexture = tex; }
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
CCWGPUSwapchain() = delete;
|
||||
|
||||
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;
|
||||
|
||||
CCWGPUSwapchainObject *_gpuSwapchainObj = nullptr;
|
||||
CCWGPUDevice *_device = nullptr;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
325
cocos/renderer/gfx-wgpu/WGPUTexture.cpp
Normal file
325
cocos/renderer/gfx-wgpu/WGPUTexture.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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 "WGPUTexture.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUSwapchain.h"
|
||||
#include "WGPUUtils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
namespace {
|
||||
CCWGPUTexture *dftCommonTexture = nullptr;
|
||||
CCWGPUTexture *dftStorageTexture = nullptr;
|
||||
|
||||
void generatePlaneViews(CCWGPUTexture *texture) {
|
||||
if (texture->getFormat() == Format::DEPTH_STENCIL) {
|
||||
auto *gpuTextureObj = texture->gpuTextureObject();
|
||||
WGPUTextureViewDescriptor depthView = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.format = WGPUTextureFormat_Depth24Plus,
|
||||
.dimension = WGPUTextureViewDimension_2D,
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = 1,
|
||||
.aspect = WGPUTextureAspect_DepthOnly,
|
||||
};
|
||||
gpuTextureObj->planeViews.emplace_back(wgpuTextureCreateView(gpuTextureObj->wgpuTexture, &depthView));
|
||||
|
||||
WGPUTextureViewDescriptor stencilView = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.format = WGPUTextureFormat_Stencil8,
|
||||
.dimension = WGPUTextureViewDimension_2D,
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = 1,
|
||||
.aspect = WGPUTextureAspect_StencilOnly,
|
||||
};
|
||||
gpuTextureObj->planeViews.emplace_back(wgpuTextureCreateView(gpuTextureObj->wgpuTexture, &stencilView));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
CCWGPUTexture::CCWGPUTexture() : Texture() {
|
||||
_gpuTextureObj = ccnew CCWGPUTextureObject;
|
||||
}
|
||||
|
||||
CCWGPUTexture::~CCWGPUTexture() {
|
||||
doDestroy();
|
||||
}
|
||||
|
||||
void CCWGPUTexture::doInit(const TextureInfo &info) {
|
||||
uint8_t depthOrArrayLayers = info.depth;
|
||||
if (info.type == TextureType::CUBE) {
|
||||
depthOrArrayLayers = 6;
|
||||
}
|
||||
|
||||
WGPUTextureDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.usage = toWGPUTextureUsage(info.usage),
|
||||
.dimension = toWGPUTextureDimension(info.type),
|
||||
.size = {info.width, info.height, depthOrArrayLayers},
|
||||
.format = toWGPUTextureFormat(info.format),
|
||||
.mipLevelCount = info.levelCount,
|
||||
.sampleCount = toWGPUSampleCount(info.samples),
|
||||
};
|
||||
|
||||
if (hasFlag(info.flags, TextureFlags::GEN_MIPMAP)) {
|
||||
descriptor.usage |= WGPUTextureUsage_RenderAttachment;
|
||||
}
|
||||
|
||||
_gpuTextureObj->wgpuTexture = wgpuDeviceCreateTexture(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().textureSize += _size;
|
||||
|
||||
WGPUTextureViewDescriptor texViewDesc = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.format = descriptor.format,
|
||||
.dimension = toWGPUTextureViewDimension(info.type),
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = _info.levelCount,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = _info.layerCount,
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
_gpuTextureObj->selfView = wgpuTextureCreateView(_gpuTextureObj->wgpuTexture, &texViewDesc);
|
||||
|
||||
generatePlaneViews(this);
|
||||
_internalChanged = true;
|
||||
} // namespace gfx
|
||||
|
||||
void CCWGPUTexture::doInit(const TextureViewInfo &info) {
|
||||
WGPUTextureViewDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.format = toWGPUTextureFormat(info.format),
|
||||
.dimension = toWGPUTextureViewDimension(info.type),
|
||||
.baseMipLevel = info.baseLevel,
|
||||
.mipLevelCount = info.levelCount,
|
||||
.baseArrayLayer = info.baseLayer,
|
||||
.arrayLayerCount = info.layerCount,
|
||||
.aspect = textureAspectTrait(info.format),
|
||||
};
|
||||
|
||||
auto *ccTexture = static_cast<CCWGPUTexture *>(info.texture);
|
||||
WGPUTexture wgpuTexture = ccTexture->gpuTextureObject()->wgpuTexture;
|
||||
_gpuTextureObj->selfView = _gpuTextureObj->wgpuTextureView = wgpuTextureCreateView(wgpuTexture, &descriptor);
|
||||
|
||||
generatePlaneViews(this);
|
||||
|
||||
_internalChanged = true;
|
||||
}
|
||||
|
||||
void CCWGPUTexture::doInit(const SwapchainTextureInfo &info) {
|
||||
if (_swapchain) {
|
||||
printf("swapchain %d, %d\n", info.width, info.height);
|
||||
auto *swapchain = static_cast<CCWGPUSwapchain *>(_swapchain);
|
||||
if (info.format == Format::DEPTH || info.format == Format::DEPTH_STENCIL) {
|
||||
WGPUTextureDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.usage = WGPUTextureUsage_RenderAttachment,
|
||||
.dimension = WGPUTextureDimension_2D,
|
||||
.size = {info.width, info.height, 1},
|
||||
.format = toWGPUTextureFormat(info.format),
|
||||
.mipLevelCount = 1,
|
||||
.sampleCount = 1,
|
||||
};
|
||||
_gpuTextureObj->wgpuTexture = wgpuDeviceCreateTexture(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().textureSize += _size;
|
||||
|
||||
WGPUTextureAspect aspect = info.format == Format::DEPTH ? WGPUTextureAspect_DepthOnly : WGPUTextureAspect_All;
|
||||
WGPUTextureViewDescriptor texViewDesc = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.format = descriptor.format,
|
||||
.dimension = WGPUTextureViewDimension_2D,
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = 1,
|
||||
.aspect = aspect,
|
||||
};
|
||||
_gpuTextureObj->selfView = wgpuTextureCreateView(_gpuTextureObj->wgpuTexture, &texViewDesc);
|
||||
|
||||
generatePlaneViews(this);
|
||||
} else {
|
||||
_gpuTextureObj->selfView = wgpuSwapChainGetCurrentTextureView(swapchain->gpuSwapchainObject()->wgpuSwapChain);
|
||||
}
|
||||
_internalChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void *CCWGPUTexture::getPlaneView(uint32_t plane) {
|
||||
if (_info.format == Format::DEPTH_STENCIL || _viewInfo.format == Format::DEPTH_STENCIL) {
|
||||
return _gpuTextureObj->planeViews[plane];
|
||||
}
|
||||
return _gpuTextureObj->selfView;
|
||||
}
|
||||
|
||||
void CCWGPUTexture::doDestroy() {
|
||||
if (_gpuTextureObj) {
|
||||
if (_gpuTextureObj->wgpuTexture) {
|
||||
CCWGPUDevice::getInstance()->moveToTrash(_gpuTextureObj->wgpuTexture);
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().textureSize -= _size;
|
||||
}
|
||||
if (_gpuTextureObj->wgpuTextureView) {
|
||||
wgpuTextureViewRelease(_gpuTextureObj->wgpuTextureView);
|
||||
}
|
||||
if (_gpuTextureObj->selfView && !_isTextureView) {
|
||||
wgpuTextureViewRelease(_gpuTextureObj->selfView);
|
||||
}
|
||||
if (!_gpuTextureObj->planeViews.empty()) {
|
||||
for (auto view : _gpuTextureObj->planeViews) {
|
||||
wgpuTextureViewRelease(view);
|
||||
}
|
||||
}
|
||||
delete _gpuTextureObj;
|
||||
_gpuTextureObj = nullptr;
|
||||
}
|
||||
_internalChanged = true;
|
||||
}
|
||||
|
||||
void CCWGPUTexture::doResize(uint32_t width, uint32_t height, uint32_t size) {
|
||||
printf("tex rsz\n");
|
||||
if (_isTextureView) {
|
||||
printf("Resize is not support on texture view!");
|
||||
return;
|
||||
}
|
||||
// swapchain color tex using canvas
|
||||
if (_swapchain && _info.format != Format::DEPTH && _info.format != Format::DEPTH_STENCIL) {
|
||||
auto *swapchain = static_cast<CCWGPUSwapchain *>(_swapchain);
|
||||
_gpuTextureObj->selfView = wgpuSwapChainGetCurrentTextureView(swapchain->gpuSwapchainObject()->wgpuSwapChain);
|
||||
return;
|
||||
}
|
||||
if (_gpuTextureObj->wgpuTexture) {
|
||||
CCWGPUDevice::getInstance()->moveToTrash(_gpuTextureObj->wgpuTexture);
|
||||
}
|
||||
if (_gpuTextureObj->wgpuTextureView) {
|
||||
wgpuTextureViewRelease(_gpuTextureObj->wgpuTextureView);
|
||||
}
|
||||
if (_gpuTextureObj->selfView) {
|
||||
wgpuTextureViewRelease(_gpuTextureObj->selfView);
|
||||
}
|
||||
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().textureSize -= _size;
|
||||
CCWGPUDevice::getInstance()->getMemoryStatus().textureSize += size;
|
||||
|
||||
uint8_t depthOrArrayLayers = _info.depth;
|
||||
if (_info.type == TextureType::CUBE) {
|
||||
depthOrArrayLayers = 6;
|
||||
}
|
||||
WGPUTextureDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.usage = toWGPUTextureUsage(_info.usage),
|
||||
.dimension = toWGPUTextureDimension(_info.type),
|
||||
.size = {width, height, depthOrArrayLayers},
|
||||
.format = toWGPUTextureFormat(_info.format),
|
||||
.mipLevelCount = _info.levelCount,
|
||||
.sampleCount = toWGPUSampleCount(_info.samples),
|
||||
};
|
||||
_gpuTextureObj->wgpuTexture = wgpuDeviceCreateTexture(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
|
||||
WGPUTextureViewDescriptor texViewDesc = {
|
||||
.nextInChain = nullptr,
|
||||
.label = nullptr,
|
||||
.format = descriptor.format,
|
||||
.dimension = toWGPUTextureViewDimension(_info.type),
|
||||
.baseMipLevel = 0,
|
||||
.mipLevelCount = _info.levelCount,
|
||||
.baseArrayLayer = 0,
|
||||
.arrayLayerCount = _info.layerCount,
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
_gpuTextureObj->selfView = wgpuTextureCreateView(_gpuTextureObj->wgpuTexture, &texViewDesc);
|
||||
|
||||
_internalChanged = true;
|
||||
}
|
||||
|
||||
void CCWGPUTexture::stamp() {
|
||||
_internalChanged = false;
|
||||
}
|
||||
|
||||
CCWGPUTexture *CCWGPUTexture::defaultCommonTexture() {
|
||||
if (!dftCommonTexture) {
|
||||
TextureInfo info = {
|
||||
.type = TextureType::TEX2D,
|
||||
.usage = TextureUsageBit::SAMPLED,
|
||||
.format = Format::RGBA8,
|
||||
.width = 2,
|
||||
.height = 2,
|
||||
.flags = TextureFlagBit::NONE,
|
||||
.layerCount = 1,
|
||||
.levelCount = 1,
|
||||
.samples = SampleCount::X1,
|
||||
.depth = 1,
|
||||
.externalRes = nullptr,
|
||||
};
|
||||
dftCommonTexture = ccnew CCWGPUTexture;
|
||||
dftCommonTexture->initialize(info);
|
||||
}
|
||||
|
||||
return dftCommonTexture;
|
||||
}
|
||||
|
||||
CCWGPUTexture *CCWGPUTexture::defaultStorageTexture() {
|
||||
if (!dftStorageTexture) {
|
||||
TextureInfo info = {
|
||||
.type = TextureType::TEX2D,
|
||||
.usage = TextureUsageBit::STORAGE,
|
||||
.format = Format::RGBA8,
|
||||
.width = 2,
|
||||
.height = 2,
|
||||
.flags = TextureFlagBit::NONE,
|
||||
.layerCount = 1,
|
||||
.levelCount = 1,
|
||||
.samples = SampleCount::X1,
|
||||
.depth = 1,
|
||||
.externalRes = nullptr,
|
||||
};
|
||||
dftStorageTexture = ccnew CCWGPUTexture;
|
||||
dftStorageTexture->initialize(info);
|
||||
}
|
||||
|
||||
return dftStorageTexture;
|
||||
}
|
||||
|
||||
CCWGPUSwapchain *CCWGPUTexture::swapchain() {
|
||||
return static_cast<CCWGPUSwapchain *>(_swapchain);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
82
cocos/renderer/gfx-wgpu/WGPUTexture.h
Normal file
82
cocos/renderer/gfx-wgpu/WGPUTexture.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-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
|
||||
#ifdef CC_WGPU_WASM
|
||||
#include "WGPUDef.h"
|
||||
#endif
|
||||
#include "WGPUDef.h"
|
||||
#include "gfx-base/GFXTexture.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
struct CCWGPUTextureObject;
|
||||
class CCWGPUSwapchain;
|
||||
|
||||
class CCWGPUTexture final : public Texture {
|
||||
public:
|
||||
CCWGPUTexture();
|
||||
~CCWGPUTexture();
|
||||
|
||||
inline CCWGPUTextureObject *gpuTextureObject() const { return _gpuTextureObj; }
|
||||
|
||||
static CCWGPUTexture *defaultCommonTexture();
|
||||
|
||||
static CCWGPUTexture *defaultStorageTexture();
|
||||
|
||||
CCWGPUSwapchain *swapchain();
|
||||
|
||||
// stamp current state
|
||||
void stamp();
|
||||
|
||||
// resource handler changed?
|
||||
inline bool internalChanged() const { return _internalChanged; }
|
||||
|
||||
inline uint32_t getDepth() const { return _info.depth; };
|
||||
inline uint32_t getLayerCount() const { return _info.layerCount; };
|
||||
inline uint32_t getLevelCount() const { return _info.levelCount; };
|
||||
inline auto getTextureType() const { return _info.type; };
|
||||
inline auto getTextureUsage() const { return _info.usage; };
|
||||
inline auto getTextureFormat() const { return _info.format; };
|
||||
inline auto getTextureSamples() const { return _info.samples; };
|
||||
inline auto getTextureFlags() const { return _info.flags; };
|
||||
|
||||
void* getPlaneView(uint32_t plane);
|
||||
|
||||
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;
|
||||
|
||||
CCWGPUTextureObject *_gpuTextureObj = nullptr;
|
||||
|
||||
bool _internalChanged = false;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
526
cocos/renderer/gfx-wgpu/WGPUUtils.cpp
Normal file
526
cocos/renderer/gfx-wgpu/WGPUUtils.cpp
Normal file
@@ -0,0 +1,526 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://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 "WGPUUtils.h"
|
||||
#include "WGPUCommandBuffer.h"
|
||||
#include "WGPUDescriptorSet.h"
|
||||
#include "WGPUDescriptorSetLayout.h"
|
||||
#include "WGPUDevice.h"
|
||||
#include "WGPUObject.h"
|
||||
#include "WGPUPipelineLayout.h"
|
||||
#include "WGPUTexture.h"
|
||||
|
||||
namespace cc::gfx {
|
||||
|
||||
void createPipelineLayoutFallback(const ccstd::vector<DescriptorSet*>& descriptorSets, PipelineLayout* pipelineLayout, bool skipEmpty) {
|
||||
ccstd::hash_t hash = descriptorSets.size() * 2 + 1;
|
||||
ccstd::hash_combine(hash, descriptorSets.size());
|
||||
std::string label = "";
|
||||
ccstd::vector<WGPUBindGroupLayout> descriptorSetLayouts;
|
||||
for (size_t i = 0; i < descriptorSets.size(); ++i) {
|
||||
auto* descriptorSet = static_cast<CCWGPUDescriptorSet*>(descriptorSets[i]);
|
||||
if (descriptorSet && descriptorSet->getHash() != 0) {
|
||||
auto* tLayout = const_cast<DescriptorSetLayout*>(descriptorSet->getLayout());
|
||||
auto* descriptorSetLayout = static_cast<CCWGPUDescriptorSetLayout*>(tLayout);
|
||||
auto* wgpuBindGroupLayout = static_cast<WGPUBindGroupLayout>(CCWGPUDescriptorSetLayout::getBindGroupLayoutByHash(descriptorSet->getHash()));
|
||||
descriptorSetLayouts.push_back(wgpuBindGroupLayout);
|
||||
ccstd::hash_combine(hash, i);
|
||||
ccstd::hash_combine(hash, descriptorSet->getHash());
|
||||
//label += std::to_string(descriptorSet->getHash()) + "-" + descriptorSet->label + "-" + std::to_string(descriptorSetLayout->getHash()) + " ";
|
||||
} else if (!skipEmpty) {
|
||||
auto bindgroup = static_cast<WGPUBindGroupLayout>(CCWGPUDescriptorSetLayout::defaultBindGroupLayout());
|
||||
descriptorSetLayouts.push_back(bindgroup);
|
||||
ccstd::hash_combine(hash, i);
|
||||
}
|
||||
}
|
||||
|
||||
auto* ccPipelineLayout = static_cast<CCWGPUPipelineLayout*>(pipelineLayout);
|
||||
WGPUPipelineLayoutDescriptor descriptor = {
|
||||
.nextInChain = nullptr,
|
||||
.label = label.c_str(),
|
||||
.bindGroupLayoutCount = descriptorSetLayouts.size(),
|
||||
.bindGroupLayouts = descriptorSetLayouts.data(),
|
||||
};
|
||||
|
||||
auto iter = ccPipelineLayout->layoutMap.find(hash);
|
||||
if (iter == ccPipelineLayout->layoutMap.end()) {
|
||||
ccPipelineLayout->layoutMap[hash] = wgpuDeviceCreatePipelineLayout(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice, &descriptor);
|
||||
ccPipelineLayout->gpuPipelineLayoutObject()->wgpuPipelineLayout = static_cast<WGPUPipelineLayout>(ccPipelineLayout->layoutMap[hash]);
|
||||
printf("create new ppl\n");
|
||||
} else {
|
||||
ccPipelineLayout->gpuPipelineLayoutObject()->wgpuPipelineLayout = static_cast<WGPUPipelineLayout>(iter->second);
|
||||
}
|
||||
ccPipelineLayout->_hash = hash;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ClearPassData {
|
||||
WGPUShaderModule vertShader = wgpuDefaultHandle;
|
||||
WGPUShaderModule fragShader = wgpuDefaultHandle;
|
||||
WGPUBindGroupLayout bindGroupLayout = wgpuDefaultHandle;
|
||||
WGPUPipelineLayout pipelineLayout = wgpuDefaultHandle;
|
||||
WGPURenderPipeline pipeline = wgpuDefaultHandle;
|
||||
};
|
||||
|
||||
struct MipmapPassData {
|
||||
WGPUShaderModule vertShader = wgpuDefaultHandle;
|
||||
WGPUShaderModule fragShader = wgpuDefaultHandle;
|
||||
WGPUSampler sampler = wgpuDefaultHandle;
|
||||
WGPUBindGroupLayout bindGroupLayout = wgpuDefaultHandle;
|
||||
WGPUPipelineLayout pipelineLayout = wgpuDefaultHandle;
|
||||
WGPURenderPipeline pipeline = wgpuDefaultHandle;
|
||||
};
|
||||
|
||||
// no need to release
|
||||
thread_local MipmapPassData mipmapData;
|
||||
thread_local ClearPassData clearPassData;
|
||||
} // namespace
|
||||
|
||||
#pragma region FIXED_PIPELINE
|
||||
void clearRect(CommandBuffer* cmdBuff, Texture* texture, const Rect& renderArea, const Color& color) {
|
||||
auto wgpuDevice = CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice;
|
||||
auto* ccTexture = static_cast<CCWGPUTexture*>(texture);
|
||||
auto format = toWGPUTextureFormat(ccTexture->getFormat());
|
||||
auto dimension = toWGPUTextureDimension(ccTexture->getTextureType());
|
||||
auto wgpuTextureView = ccTexture->gpuTextureObject()->selfView;
|
||||
|
||||
if (!clearPassData.vertShader) {
|
||||
const char* clearQuadVert = R"(
|
||||
struct VertexOutput {
|
||||
@builtin(position) Position : vec4<f32>,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {
|
||||
var pos = array<vec2<f32>, 6>(
|
||||
vec2<f32>( 1.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>( 1.0, 1.0),
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>(-1.0, 1.0)
|
||||
);
|
||||
|
||||
var output : VertexOutput;
|
||||
output.Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
return output;
|
||||
}
|
||||
)";
|
||||
|
||||
const char* clearQuadFrag = R"(
|
||||
struct ClearColor {
|
||||
color: vec4<f32>,
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<uniform> clearColor : ClearColor;
|
||||
|
||||
@fragment
|
||||
fn frag_main() -> @location(0) vec4<f32> {
|
||||
return clearColor.color;
|
||||
}
|
||||
)";
|
||||
|
||||
WGPUShaderModuleWGSLDescriptor wgslShaderDescVert{};
|
||||
wgslShaderDescVert.code = clearQuadVert;
|
||||
wgslShaderDescVert.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
||||
WGPUShaderModuleDescriptor shaderDescVert;
|
||||
shaderDescVert.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgslShaderDescVert);
|
||||
shaderDescVert.label = "clearQuadVert";
|
||||
clearPassData.vertShader = wgpuDeviceCreateShaderModule(wgpuDevice, &shaderDescVert);
|
||||
|
||||
WGPUShaderModuleWGSLDescriptor wgslShaderDescFrag{};
|
||||
wgslShaderDescFrag.code = clearQuadFrag;
|
||||
wgslShaderDescFrag.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
||||
WGPUShaderModuleDescriptor shaderDescFrag;
|
||||
shaderDescFrag.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgslShaderDescFrag);
|
||||
shaderDescFrag.label = "clearQuadFrag";
|
||||
clearPassData.fragShader = wgpuDeviceCreateShaderModule(wgpuDevice, &shaderDescFrag);
|
||||
|
||||
WGPUBindGroupLayoutEntry bufferEntry{};
|
||||
bufferEntry.binding = 0;
|
||||
bufferEntry.visibility = WGPUShaderStage_Fragment;
|
||||
bufferEntry.texture.sampleType = WGPUTextureSampleType_Undefined;
|
||||
bufferEntry.buffer.type = WGPUBufferBindingType_Uniform;
|
||||
bufferEntry.buffer.hasDynamicOffset = false;
|
||||
bufferEntry.buffer.minBindingSize = 16;
|
||||
bufferEntry.sampler.type = WGPUSamplerBindingType_Undefined;
|
||||
bufferEntry.storageTexture.access = WGPUStorageTextureAccess_Undefined;
|
||||
|
||||
WGPUBindGroupLayoutDescriptor bgLayoutDesc{};
|
||||
bgLayoutDesc.label = "clearPassBGLayout";
|
||||
bgLayoutDesc.entryCount = 1;
|
||||
bgLayoutDesc.entries = &bufferEntry;
|
||||
clearPassData.bindGroupLayout = wgpuDeviceCreateBindGroupLayout(wgpuDevice, &bgLayoutDesc);
|
||||
|
||||
WGPUPipelineLayoutDescriptor pipelineLayoutDesc{};
|
||||
pipelineLayoutDesc.label = "clearPassPipelineLayout";
|
||||
pipelineLayoutDesc.bindGroupLayoutCount = 1;
|
||||
pipelineLayoutDesc.bindGroupLayouts = &clearPassData.bindGroupLayout;
|
||||
clearPassData.pipelineLayout = wgpuDeviceCreatePipelineLayout(wgpuDevice, &pipelineLayoutDesc);
|
||||
|
||||
WGPUVertexState vertexState{};
|
||||
vertexState.module = clearPassData.vertShader;
|
||||
vertexState.entryPoint = "vert_main";
|
||||
|
||||
WGPUPrimitiveState primitiveState{};
|
||||
primitiveState.topology = WGPUPrimitiveTopology_TriangleList;
|
||||
primitiveState.stripIndexFormat = WGPUIndexFormat_Undefined;
|
||||
primitiveState.frontFace = WGPUFrontFace_CCW;
|
||||
primitiveState.cullMode = WGPUCullMode_None;
|
||||
|
||||
WGPUColorTargetState colorState{};
|
||||
colorState.format = format;
|
||||
colorState.writeMask = WGPUColorWriteMask_All;
|
||||
|
||||
WGPUFragmentState fragState{};
|
||||
fragState.module = clearPassData.fragShader;
|
||||
fragState.entryPoint = "frag_main";
|
||||
fragState.targetCount = 1;
|
||||
fragState.targets = &colorState;
|
||||
|
||||
WGPUMultisampleState multisample{};
|
||||
multisample.count = 1;
|
||||
multisample.alphaToCoverageEnabled = false;
|
||||
multisample.mask = 0xFFFFFFFF;
|
||||
|
||||
WGPURenderPipelineDescriptor pipelineDesc{};
|
||||
pipelineDesc.label = "clearPassPipeline";
|
||||
pipelineDesc.layout = clearPassData.pipelineLayout;
|
||||
pipelineDesc.vertex = vertexState;
|
||||
pipelineDesc.primitive = primitiveState;
|
||||
pipelineDesc.fragment = &fragState;
|
||||
pipelineDesc.depthStencil = nullptr;
|
||||
pipelineDesc.multisample = multisample;
|
||||
clearPassData.pipeline = wgpuDeviceCreateRenderPipeline(wgpuDevice, &pipelineDesc);
|
||||
}
|
||||
|
||||
CC_ASSERT_GT(i, 0);
|
||||
auto cmdBuffCommandEncoder = static_cast<CCWGPUCommandBuffer*>(cmdBuff)->gpuCommandBufferObject()->wgpuCommandEncoder;
|
||||
auto commandEncoder = cmdBuffCommandEncoder;
|
||||
if (!cmdBuffCommandEncoder) {
|
||||
commandEncoder = wgpuDeviceCreateCommandEncoder(wgpuDevice, nullptr);
|
||||
}
|
||||
|
||||
auto dstView = wgpuTextureView;
|
||||
|
||||
WGPUBufferDescriptor bufferDesc{};
|
||||
bufferDesc.usage = WGPUBufferUsage_Uniform;
|
||||
bufferDesc.size = 16;
|
||||
bufferDesc.mappedAtCreation = true;
|
||||
auto uniformBuffer = wgpuDeviceCreateBuffer(wgpuDevice, &bufferDesc);
|
||||
|
||||
float colorArr[4] = {color.x, color.y, color.z, color.w};
|
||||
auto* mappedBuffer = wgpuBufferGetMappedRange(uniformBuffer, 0, 16);
|
||||
memcpy(mappedBuffer, colorArr, 16);
|
||||
wgpuBufferUnmap(uniformBuffer);
|
||||
|
||||
WGPUBindGroupEntry entry{};
|
||||
entry.binding = 0;
|
||||
entry.sampler = wgpuDefaultHandle;
|
||||
entry.buffer = uniformBuffer;
|
||||
entry.offset = 0;
|
||||
entry.size = 16;
|
||||
entry.textureView = wgpuDefaultHandle;
|
||||
|
||||
WGPUBindGroupDescriptor bindgroupDesc{};
|
||||
bindgroupDesc.layout = clearPassData.bindGroupLayout;
|
||||
bindgroupDesc.entryCount = 1;
|
||||
bindgroupDesc.entries = &entry;
|
||||
auto bindGroup = wgpuDeviceCreateBindGroup(wgpuDevice, &bindgroupDesc);
|
||||
|
||||
WGPURenderPassColorAttachment colorAttachment{};
|
||||
colorAttachment.view = dstView;
|
||||
colorAttachment.resolveTarget = wgpuDefaultHandle;
|
||||
colorAttachment.loadOp = WGPULoadOp_Load;
|
||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||
colorAttachment.clearValue = {0.88, 0.88, 0.88, 1.0};
|
||||
|
||||
WGPURenderPassDescriptor rpDesc{};
|
||||
rpDesc.colorAttachmentCount = 1;
|
||||
rpDesc.colorAttachments = &colorAttachment;
|
||||
rpDesc.depthStencilAttachment = nullptr;
|
||||
rpDesc.occlusionQuerySet = nullptr;
|
||||
rpDesc.timestampWriteCount = 0;
|
||||
rpDesc.timestampWrites = nullptr;
|
||||
auto renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &rpDesc);
|
||||
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, clearPassData.pipeline);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroup, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetViewport(renderPassEncoder, renderArea.x, renderArea.y, renderArea.width, renderArea.height, 0.0F, 1.0F);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderArea.x, renderArea.y, renderArea.width, renderArea.height);
|
||||
wgpuRenderPassEncoderDraw(renderPassEncoder, 6, 1, 0, 0);
|
||||
wgpuRenderPassEncoderEnd(renderPassEncoder);
|
||||
wgpuRenderPassEncoderRelease(renderPassEncoder);
|
||||
wgpuBindGroupRelease(bindGroup);
|
||||
wgpuBufferRelease(uniformBuffer);
|
||||
|
||||
if (!cmdBuffCommandEncoder) {
|
||||
auto commandBuffer = wgpuCommandEncoderFinish(commandEncoder, nullptr);
|
||||
wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &commandBuffer);
|
||||
wgpuCommandEncoderRelease(commandEncoder);
|
||||
wgpuCommandBufferRelease(commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void genMipMap(Texture* texture, uint8_t fromLevel, uint8_t levelCount, uint32_t baseLayer, CommandBuffer* cmdBuff) {
|
||||
auto wgpuDevice = CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuDevice;
|
||||
auto* ccTexture = static_cast<CCWGPUTexture*>(texture);
|
||||
auto format = toWGPUTextureFormat(ccTexture->getFormat());
|
||||
auto dimension = toWGPUTextureDimension(ccTexture->getTextureType());
|
||||
auto* wgpuTexture = ccTexture->gpuTextureObject()->wgpuTexture;
|
||||
|
||||
if (!mipmapData.vertShader) {
|
||||
// WGPUBufferDescriptor bufferDesc;
|
||||
// bufferDesc.usage = WGPUBufferUsage_Vertex;
|
||||
// bufferDesc.size = 120;
|
||||
// bufferDesc.mappedAtCreation = true;
|
||||
// mipmapData.vertexBuffer = wgpuDeviceCreateBuffer(wgpuDevice, &bufferDesc);
|
||||
|
||||
// auto* mappedBuffer = wgpuBufferGetMappedRange(mipmapData.vertexBuffer, 0, 120);
|
||||
// memcpy(mappedBuffer, quadVert, 120);
|
||||
// wgpuBufferUnmap(mipmapData.vertexBuffer);
|
||||
|
||||
// https://github.com/austinEng/webgpu-samples/blob/main/src/shaders/fullscreenTexturedQuad.wgsl
|
||||
const char* textureQuadVert = R"(
|
||||
struct VertexOutput {
|
||||
@builtin(position) Position : vec4<f32>,
|
||||
@location(0) fragUV : vec2<f32>,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vert_main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {
|
||||
var pos = array<vec2<f32>, 6>(
|
||||
vec2<f32>( 1.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>( 1.0, 1.0),
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>(-1.0, 1.0)
|
||||
);
|
||||
|
||||
var uv = array<vec2<f32>, 6>(
|
||||
vec2<f32>(1.0, 0.0),
|
||||
vec2<f32>(1.0, 1.0),
|
||||
vec2<f32>(0.0, 1.0),
|
||||
vec2<f32>(1.0, 0.0),
|
||||
vec2<f32>(0.0, 1.0),
|
||||
vec2<f32>(0.0, 0.0)
|
||||
);
|
||||
|
||||
var output : VertexOutput;
|
||||
output.Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
output.fragUV = uv[VertexIndex];
|
||||
return output;
|
||||
}
|
||||
)";
|
||||
|
||||
const char* textureQuadFrag = R"(
|
||||
@group(0) @binding(0) var mySampler : sampler;
|
||||
@group(0) @binding(1) var myTexture : texture_2d<f32>;
|
||||
|
||||
@fragment
|
||||
fn frag_main(@location(0) fragUV : vec2<f32>) -> @location(0) vec4<f32> {
|
||||
return textureSample(myTexture, mySampler, fragUV);
|
||||
}
|
||||
)";
|
||||
|
||||
WGPUSamplerDescriptor samplerDesc{};
|
||||
samplerDesc.label = "filterSampler";
|
||||
samplerDesc.addressModeU = WGPUAddressMode_MirrorRepeat;
|
||||
samplerDesc.addressModeV = WGPUAddressMode_MirrorRepeat;
|
||||
samplerDesc.addressModeW = WGPUAddressMode_MirrorRepeat;
|
||||
samplerDesc.magFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.minFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Linear;
|
||||
samplerDesc.lodMinClamp = 0.0;
|
||||
samplerDesc.lodMaxClamp = 32.0;
|
||||
samplerDesc.compare = WGPUCompareFunction_Undefined;
|
||||
samplerDesc.maxAnisotropy = 1;
|
||||
mipmapData.sampler = wgpuDeviceCreateSampler(wgpuDevice, &samplerDesc);
|
||||
|
||||
WGPUShaderModuleWGSLDescriptor wgslShaderDescVert{};
|
||||
wgslShaderDescVert.code = textureQuadVert;
|
||||
wgslShaderDescVert.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
||||
WGPUShaderModuleDescriptor shaderDescVert;
|
||||
shaderDescVert.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgslShaderDescVert);
|
||||
shaderDescVert.label = "textureQuadVert";
|
||||
mipmapData.vertShader = wgpuDeviceCreateShaderModule(wgpuDevice, &shaderDescVert);
|
||||
|
||||
WGPUShaderModuleWGSLDescriptor wgslShaderDescFrag{};
|
||||
wgslShaderDescFrag.code = textureQuadFrag;
|
||||
wgslShaderDescFrag.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
|
||||
WGPUShaderModuleDescriptor shaderDescFrag;
|
||||
shaderDescFrag.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&wgslShaderDescFrag);
|
||||
shaderDescFrag.label = "textureQuadFrag";
|
||||
mipmapData.fragShader = wgpuDeviceCreateShaderModule(wgpuDevice, &shaderDescFrag);
|
||||
|
||||
WGPUBindGroupLayoutEntry samplerEntry{};
|
||||
samplerEntry.binding = 0;
|
||||
samplerEntry.visibility = WGPUShaderStage_Fragment;
|
||||
samplerEntry.sampler.type = WGPUSamplerBindingType_Filtering;
|
||||
samplerEntry.buffer.type = WGPUBufferBindingType_Undefined;
|
||||
samplerEntry.texture.sampleType = WGPUTextureSampleType_Undefined;
|
||||
samplerEntry.storageTexture.access = WGPUStorageTextureAccess_Undefined;
|
||||
|
||||
WGPUBindGroupLayoutEntry textureEntry{};
|
||||
textureEntry.binding = 1;
|
||||
textureEntry.visibility = WGPUShaderStage_Fragment;
|
||||
textureEntry.texture.sampleType = textureSampleTypeTrait(ccTexture->getFormat());
|
||||
textureEntry.texture.viewDimension = WGPUTextureViewDimension_2D;
|
||||
textureEntry.texture.multisampled = false;
|
||||
textureEntry.buffer.type = WGPUBufferBindingType_Undefined;
|
||||
textureEntry.sampler.type = WGPUSamplerBindingType_Undefined;
|
||||
textureEntry.storageTexture.access = WGPUStorageTextureAccess_Undefined;
|
||||
WGPUBindGroupLayoutEntry entries[2] = {samplerEntry, textureEntry};
|
||||
|
||||
WGPUBindGroupLayoutDescriptor bgLayoutDesc{};
|
||||
bgLayoutDesc.label = "fullscreenTexturedQuadBGLayout";
|
||||
bgLayoutDesc.entryCount = 2;
|
||||
bgLayoutDesc.entries = entries;
|
||||
mipmapData.bindGroupLayout = wgpuDeviceCreateBindGroupLayout(wgpuDevice, &bgLayoutDesc);
|
||||
|
||||
WGPUPipelineLayoutDescriptor pipelineLayoutDesc{};
|
||||
pipelineLayoutDesc.label = "fullscreenTexturedQuadPipelineLayout";
|
||||
pipelineLayoutDesc.bindGroupLayoutCount = 1;
|
||||
pipelineLayoutDesc.bindGroupLayouts = &mipmapData.bindGroupLayout;
|
||||
mipmapData.pipelineLayout = wgpuDeviceCreatePipelineLayout(wgpuDevice, &pipelineLayoutDesc);
|
||||
|
||||
WGPUVertexState vertexState{};
|
||||
vertexState.module = mipmapData.vertShader;
|
||||
vertexState.entryPoint = "vert_main";
|
||||
vertexState.bufferCount = 0;
|
||||
vertexState.buffers = nullptr;
|
||||
|
||||
WGPUPrimitiveState primitiveState{};
|
||||
primitiveState.topology = WGPUPrimitiveTopology_TriangleList;
|
||||
primitiveState.stripIndexFormat = WGPUIndexFormat_Undefined;
|
||||
primitiveState.frontFace = WGPUFrontFace_CCW;
|
||||
primitiveState.cullMode = WGPUCullMode_None;
|
||||
|
||||
WGPUColorTargetState colorState{};
|
||||
colorState.format = format;
|
||||
colorState.writeMask = WGPUColorWriteMask_All;
|
||||
|
||||
WGPUFragmentState fragState{};
|
||||
fragState.module = mipmapData.fragShader;
|
||||
fragState.entryPoint = "frag_main";
|
||||
fragState.targetCount = 1;
|
||||
fragState.targets = &colorState;
|
||||
|
||||
WGPUMultisampleState multisample{};
|
||||
multisample.count = 1;
|
||||
multisample.alphaToCoverageEnabled = false;
|
||||
multisample.mask = 0xFFFFFFFF;
|
||||
|
||||
WGPURenderPipelineDescriptor pipelineDesc{};
|
||||
pipelineDesc.label = "fullscreenTexturedQuadPipeline";
|
||||
pipelineDesc.layout = mipmapData.pipelineLayout;
|
||||
pipelineDesc.vertex = vertexState;
|
||||
pipelineDesc.primitive = primitiveState;
|
||||
pipelineDesc.fragment = &fragState;
|
||||
pipelineDesc.depthStencil = nullptr;
|
||||
pipelineDesc.multisample = multisample;
|
||||
mipmapData.pipeline = wgpuDeviceCreateRenderPipeline(wgpuDevice, &pipelineDesc);
|
||||
}
|
||||
|
||||
WGPUTextureViewDescriptor desc{};
|
||||
desc.format = format;
|
||||
desc.dimension = WGPUTextureViewDimension_2D;
|
||||
desc.baseMipLevel = fromLevel;
|
||||
desc.mipLevelCount = 1;
|
||||
desc.baseArrayLayer = baseLayer;
|
||||
desc.arrayLayerCount = 1;
|
||||
desc.aspect = WGPUTextureAspect_All;
|
||||
|
||||
CC_ASSERT_GT(i, 0);
|
||||
auto cmdBuffCommandEncoder = static_cast<CCWGPUCommandBuffer*>(cmdBuff)->gpuCommandBufferObject()->wgpuCommandEncoder;
|
||||
auto commandEncoder = cmdBuffCommandEncoder;
|
||||
if (!cmdBuffCommandEncoder) {
|
||||
commandEncoder = wgpuDeviceCreateCommandEncoder(wgpuDevice, nullptr);
|
||||
}
|
||||
|
||||
for (uint8_t i = fromLevel; i < fromLevel + levelCount; ++i) {
|
||||
desc.baseMipLevel = i - 1;
|
||||
auto srcView = wgpuTextureCreateView(wgpuTexture, &desc);
|
||||
desc.baseMipLevel = i;
|
||||
desc.baseArrayLayer = baseLayer;
|
||||
desc.arrayLayerCount = 1;
|
||||
auto dstView = wgpuTextureCreateView(wgpuTexture, &desc);
|
||||
|
||||
WGPUBindGroupEntry entries[2];
|
||||
entries[0].nextInChain = nullptr;
|
||||
entries[0].binding = 0;
|
||||
entries[0].sampler = mipmapData.sampler;
|
||||
entries[0].buffer = wgpuDefaultHandle;
|
||||
entries[0].textureView = wgpuDefaultHandle;
|
||||
|
||||
entries[1].nextInChain = nullptr;
|
||||
entries[1].binding = 1;
|
||||
entries[1].textureView = srcView;
|
||||
entries[1].buffer = wgpuDefaultHandle;
|
||||
entries[1].sampler = wgpuDefaultHandle;
|
||||
|
||||
WGPUBindGroupDescriptor bindgroupDesc{};
|
||||
bindgroupDesc.layout = mipmapData.bindGroupLayout;
|
||||
bindgroupDesc.entryCount = 2;
|
||||
bindgroupDesc.entries = entries;
|
||||
auto bindGroup = wgpuDeviceCreateBindGroup(wgpuDevice, &bindgroupDesc);
|
||||
|
||||
WGPURenderPassColorAttachment colorAttachment;
|
||||
colorAttachment.view = dstView;
|
||||
colorAttachment.resolveTarget = wgpuDefaultHandle;
|
||||
colorAttachment.loadOp = WGPULoadOp_Clear;
|
||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||
colorAttachment.clearValue = {0.88, 0.88, 0.88, 1.0};
|
||||
|
||||
WGPURenderPassDescriptor rpDesc{};
|
||||
rpDesc.label = nullptr;
|
||||
rpDesc.colorAttachmentCount = 1;
|
||||
rpDesc.colorAttachments = &colorAttachment;
|
||||
rpDesc.depthStencilAttachment = nullptr;
|
||||
rpDesc.occlusionQuerySet = nullptr;
|
||||
rpDesc.timestampWriteCount = 0;
|
||||
rpDesc.timestampWrites = nullptr;
|
||||
auto renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &rpDesc);
|
||||
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, mipmapData.pipeline);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroup, 0, nullptr);
|
||||
wgpuRenderPassEncoderDraw(renderPassEncoder, 6, 1, 0, 0);
|
||||
wgpuRenderPassEncoderEnd(renderPassEncoder);
|
||||
wgpuRenderPassEncoderRelease(renderPassEncoder);
|
||||
wgpuBindGroupRelease(bindGroup);
|
||||
wgpuTextureViewRelease(srcView);
|
||||
wgpuTextureViewRelease(dstView);
|
||||
}
|
||||
|
||||
if (!cmdBuffCommandEncoder) {
|
||||
auto commandBuffer = wgpuCommandEncoderFinish(commandEncoder, nullptr);
|
||||
wgpuQueueSubmit(CCWGPUDevice::getInstance()->gpuDeviceObject()->wgpuQueue, 1, &commandBuffer);
|
||||
wgpuCommandEncoderRelease(commandEncoder);
|
||||
wgpuCommandBufferRelease(commandBuffer);
|
||||
}
|
||||
}
|
||||
#pragma endregion FIXED_PIPELINE
|
||||
|
||||
} // namespace cc::gfx
|
||||
674
cocos/renderer/gfx-wgpu/WGPUUtils.h
Normal file
674
cocos/renderer/gfx-wgpu/WGPUUtils.h
Normal file
@@ -0,0 +1,674 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://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 <webgpu/webgpu.h>
|
||||
#include "base/std/container/vector.h"
|
||||
#include "cocos/base/Macros.h"
|
||||
#include "cocos/base/TypeDef.h"
|
||||
#include "gfx-base/GFXDef-common.h"
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
static WGPULoadOp toWGPULoadOp(LoadOp op) {
|
||||
switch (op) {
|
||||
case LoadOp::CLEAR:
|
||||
return WGPULoadOp::WGPULoadOp_Clear;
|
||||
case LoadOp::LOAD:
|
||||
return WGPULoadOp::WGPULoadOp_Load;
|
||||
case LoadOp::DISCARD:
|
||||
return WGPULoadOp::WGPULoadOp_Clear;
|
||||
default:
|
||||
return WGPULoadOp::WGPULoadOp_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUStoreOp toWGPUStoreOp(StoreOp op) {
|
||||
switch (op) {
|
||||
case StoreOp::STORE:
|
||||
return WGPUStoreOp::WGPUStoreOp_Store;
|
||||
case StoreOp::DISCARD:
|
||||
return WGPUStoreOp::WGPUStoreOp_Discard;
|
||||
default:
|
||||
return WGPUStoreOp::WGPUStoreOp_Discard;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUTextureUsageFlags toWGPUTextureUsage(TextureUsage usage) {
|
||||
if (usage == TextureUsageBit::NONE)
|
||||
return WGPUTextureUsage::WGPUTextureUsage_CopyDst;
|
||||
|
||||
WGPUTextureUsageFlags res = WGPUTextureUsage::WGPUTextureUsage_None;
|
||||
if (hasFlag(usage, TextureUsageBit::TRANSFER_SRC)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_CopySrc;
|
||||
}
|
||||
if (hasFlag(usage, TextureUsageBit::TRANSFER_DST)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_CopyDst;
|
||||
}
|
||||
if (hasFlag(usage, TextureUsageBit::SAMPLED)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_TextureBinding;
|
||||
}
|
||||
if (hasFlag(usage, TextureUsageBit::STORAGE)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_StorageBinding;
|
||||
}
|
||||
if (hasFlag(usage, TextureUsageBit::INPUT_ATTACHMENT)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_TextureBinding;
|
||||
}
|
||||
if (hasFlag(usage, TextureUsageBit::COLOR_ATTACHMENT)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_RenderAttachment;
|
||||
}
|
||||
if (hasFlag(usage, TextureUsageBit::DEPTH_STENCIL_ATTACHMENT)) {
|
||||
res |= WGPUTextureUsage::WGPUTextureUsage_RenderAttachment;
|
||||
}
|
||||
// TODO_Zeqiang: unexpected texture copy in pipeline.
|
||||
// if (!hasFlag(usage, TextureUsageBit::TRANSFER_DST))
|
||||
// res |= WGPUTextureUsage::WGPUTextureUsage_CopyDst;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static WGPUTextureDimension toWGPUTextureDimension(TextureType type) {
|
||||
switch (type) {
|
||||
case TextureType::TEX1D:
|
||||
case TextureType::TEX1D_ARRAY:
|
||||
return WGPUTextureDimension::WGPUTextureDimension_1D;
|
||||
case TextureType::TEX2D:
|
||||
case TextureType::TEX2D_ARRAY:
|
||||
case TextureType::CUBE:
|
||||
return WGPUTextureDimension::WGPUTextureDimension_2D;
|
||||
case TextureType::TEX3D:
|
||||
return WGPUTextureDimension::WGPUTextureDimension_3D;
|
||||
default:
|
||||
printf("Unsupport type: %d\n", static_cast<int>(type));
|
||||
return WGPUTextureDimension::WGPUTextureDimension_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUTextureViewDimension toWGPUTextureViewDimension(TextureType type) {
|
||||
switch (type) {
|
||||
case TextureType::TEX1D:
|
||||
case TextureType::TEX1D_ARRAY:
|
||||
return WGPUTextureViewDimension::WGPUTextureViewDimension_1D;
|
||||
case TextureType::TEX2D:
|
||||
return WGPUTextureViewDimension::WGPUTextureViewDimension_2D;
|
||||
case TextureType::TEX2D_ARRAY:
|
||||
return WGPUTextureViewDimension::WGPUTextureViewDimension_2DArray;
|
||||
case TextureType::CUBE:
|
||||
return WGPUTextureViewDimension::WGPUTextureViewDimension_Cube;
|
||||
case TextureType::TEX3D:
|
||||
return WGPUTextureViewDimension::WGPUTextureViewDimension_3D;
|
||||
default:
|
||||
printf("Unsupport type %d\n", static_cast<int>(type));
|
||||
return WGPUTextureViewDimension::WGPUTextureViewDimension_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUTextureSampleType textureSampleTypeTrait(Format format) {
|
||||
switch (format) {
|
||||
case Format::R8:
|
||||
case Format::R8SN:
|
||||
case Format::RG8:
|
||||
case Format::RGBA8:
|
||||
case Format::BGRA8:
|
||||
case Format::RG8SN:
|
||||
case Format::SRGB8_A8:
|
||||
case Format::RGB10A2:
|
||||
case Format::RGBA16F:
|
||||
return WGPUTextureSampleType::WGPUTextureSampleType_Float;
|
||||
case Format::R8UI:
|
||||
case Format::R16UI:
|
||||
case Format::RG8UI:
|
||||
case Format::R32UI:
|
||||
case Format::RG16UI:
|
||||
case Format::RGBA8UI:
|
||||
case Format::RG32UI:
|
||||
case Format::RGBA32UI:
|
||||
case Format::RGBA16UI:
|
||||
case Format::DEPTH_STENCIL:
|
||||
return WGPUTextureSampleType::WGPUTextureSampleType_Uint;
|
||||
case Format::R8I:
|
||||
case Format::R16I:
|
||||
case Format::RG8I:
|
||||
case Format::RG16I:
|
||||
case Format::RGBA8I:
|
||||
case Format::RG32I:
|
||||
case Format::RGBA16I:
|
||||
case Format::RGBA32I:
|
||||
case Format::R32I:
|
||||
return WGPUTextureSampleType::WGPUTextureSampleType_Sint;
|
||||
case Format::R16F:
|
||||
case Format::R32F:
|
||||
case Format::RG16F:
|
||||
case Format::R11G11B10F:
|
||||
case Format::RG32F:
|
||||
case Format::RGBA32F:
|
||||
return WGPUTextureSampleType::WGPUTextureSampleType_UnfilterableFloat;
|
||||
case Format::DEPTH:
|
||||
return WGPUTextureSampleType::WGPUTextureSampleType_Depth;
|
||||
default:
|
||||
printf("Unsupport texture sample type yet, github@hana-alice to fix.\n");
|
||||
return WGPUTextureSampleType::WGPUTextureSampleType_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isFilterable(Format format) {
|
||||
return textureSampleTypeTrait(format) != WGPUTextureSampleType_UnfilterableFloat;
|
||||
}
|
||||
|
||||
static WGPUTextureAspect textureAspectTrait(Format format) {
|
||||
switch (format) {
|
||||
case Format::DEPTH:
|
||||
return WGPUTextureAspect_DepthOnly;
|
||||
case Format::DEPTH_STENCIL:
|
||||
return WGPUTextureAspect_All;
|
||||
default:
|
||||
return WGPUTextureAspect_All;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUTextureFormat toWGPUTextureFormat(Format format) {
|
||||
switch (format) {
|
||||
case Format::UNKNOWN:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_Undefined;
|
||||
case Format::R8:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R8Unorm;
|
||||
case Format::R8SN:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R8Snorm;
|
||||
case Format::R8UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R8Uint;
|
||||
case Format::R8I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R8Sint;
|
||||
case Format::R16UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R16Uint;
|
||||
case Format::R16I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R16Sint;
|
||||
case Format::R16F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R16Float;
|
||||
case Format::RG8:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG8Unorm;
|
||||
case Format::RG8SN:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG8Snorm;
|
||||
case Format::RG8UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG8Uint;
|
||||
case Format::RG8I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG8Sint;
|
||||
case Format::R32F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R32Float;
|
||||
case Format::R32UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R32Uint;
|
||||
case Format::R32I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_R32Sint;
|
||||
case Format::RG16UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG16Uint;
|
||||
case Format::RG16I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG16Sint;
|
||||
case Format::RG16F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG16Float;
|
||||
case Format::RGBA8:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA8Unorm;
|
||||
case Format::SRGB8_A8:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA8UnormSrgb;
|
||||
case Format::RGBA8SN:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA8Snorm;
|
||||
case Format::RGBA8UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA8Uint;
|
||||
case Format::RGBA8I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA8Sint;
|
||||
case Format::BGRA8:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BGRA8Unorm;
|
||||
case Format::RGB10A2:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGB10A2Unorm;
|
||||
case Format::R11G11B10F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG11B10Ufloat;
|
||||
case Format::RGB9E5:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGB9E5Ufloat;
|
||||
case Format::RG32F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG32Float;
|
||||
case Format::RG32UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG32Uint;
|
||||
case Format::RG32I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RG32Sint;
|
||||
case Format::RGBA16UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA16Uint;
|
||||
case Format::RGBA16I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA16Sint;
|
||||
case Format::RGBA16F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA16Float;
|
||||
case Format::RGBA32F:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA32Float;
|
||||
case Format::RGBA32UI:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA32Uint;
|
||||
case Format::RGBA32I:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_RGBA32Sint;
|
||||
case Format::DEPTH:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_Depth24Plus;
|
||||
case Format::DEPTH_STENCIL:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_Depth24PlusStencil8;
|
||||
case Format::BC1:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC1RGBAUnorm;
|
||||
case Format::BC1_SRGB:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC1RGBAUnormSrgb;
|
||||
case Format::BC2:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC2RGBAUnorm;
|
||||
case Format::BC2_SRGB:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC2RGBAUnormSrgb;
|
||||
case Format::BC3:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC3RGBAUnorm;
|
||||
case Format::BC4:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC4RUnorm;
|
||||
case Format::BC4_SNORM:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC4RSnorm;
|
||||
case Format::BC5:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC5RGUnorm;
|
||||
case Format::BC5_SNORM:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC5RGSnorm;
|
||||
case Format::BC6H_UF16:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC6HRGBUfloat;
|
||||
case Format::BC6H_SF16:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC6HRGBFloat;
|
||||
case Format::BC7:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC7RGBAUnorm;
|
||||
case Format::BC7_SRGB:
|
||||
return WGPUTextureFormat::WGPUTextureFormat_BC7RGBAUnormSrgb;
|
||||
default:
|
||||
printf("Unsupport WebGPU texture format %d\n", static_cast<int>(format));
|
||||
return WGPUTextureFormat::WGPUTextureFormat_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUAddressMode toWGPUAddressMode(Address addrMode) {
|
||||
switch (addrMode) {
|
||||
case Address::WRAP:
|
||||
return WGPUAddressMode::WGPUAddressMode_Repeat;
|
||||
case Address::CLAMP:
|
||||
return WGPUAddressMode::WGPUAddressMode_ClampToEdge;
|
||||
case Address::BORDER:
|
||||
return WGPUAddressMode::WGPUAddressMode_ClampToEdge;
|
||||
case Address::MIRROR:
|
||||
return WGPUAddressMode::WGPUAddressMode_MirrorRepeat;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUMipmapFilterMode toWGPUMipmapFilterMode(Filter filter) {
|
||||
switch (filter) {
|
||||
case Filter::NONE:
|
||||
return WGPUMipmapFilterMode::WGPUMipmapFilterMode_Nearest;
|
||||
case Filter::POINT:
|
||||
return WGPUMipmapFilterMode::WGPUMipmapFilterMode_Nearest;
|
||||
case Filter::LINEAR:
|
||||
return WGPUMipmapFilterMode::WGPUMipmapFilterMode_Linear;
|
||||
case Filter::ANISOTROPIC:
|
||||
return WGPUMipmapFilterMode::WGPUMipmapFilterMode_Linear;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUFilterMode toWGPUFilterMode(Filter filter) {
|
||||
switch (filter) {
|
||||
case Filter::NONE:
|
||||
return WGPUFilterMode::WGPUFilterMode_Nearest;
|
||||
case Filter::POINT:
|
||||
return WGPUFilterMode::WGPUFilterMode_Nearest;
|
||||
case Filter::LINEAR:
|
||||
return WGPUFilterMode::WGPUFilterMode_Linear;
|
||||
case Filter::ANISOTROPIC:
|
||||
return WGPUFilterMode::WGPUFilterMode_Linear;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUCompareFunction toWGPUCompareFunction(ComparisonFunc compareFunc) {
|
||||
switch (compareFunc) {
|
||||
case ComparisonFunc::NEVER:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_Never;
|
||||
case ComparisonFunc::LESS:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_Less;
|
||||
case ComparisonFunc::EQUAL:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_Equal;
|
||||
case ComparisonFunc::LESS_EQUAL:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_LessEqual;
|
||||
case ComparisonFunc::GREATER:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_Greater;
|
||||
case ComparisonFunc::NOT_EQUAL:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_NotEqual;
|
||||
case ComparisonFunc::GREATER_EQUAL:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_GreaterEqual;
|
||||
case ComparisonFunc::ALWAYS:
|
||||
return WGPUCompareFunction::WGPUCompareFunction_Always;
|
||||
default:
|
||||
printf("Unsupport compareFunc: %d\n", static_cast<int>(compareFunc));
|
||||
return WGPUCompareFunction::WGPUCompareFunction_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUStencilOperation toWGPUStencilOperation(StencilOp stencilOp) {
|
||||
switch (stencilOp) {
|
||||
case StencilOp::ZERO:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_Zero;
|
||||
case StencilOp::KEEP:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_Keep;
|
||||
case StencilOp::REPLACE:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_Replace;
|
||||
case StencilOp::INCR:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_IncrementClamp;
|
||||
case StencilOp::DECR:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_DecrementClamp;
|
||||
case StencilOp::INVERT:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_Invert;
|
||||
case StencilOp::INCR_WRAP:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_IncrementWrap;
|
||||
case StencilOp::DECR_WRAP:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_DecrementWrap;
|
||||
default:
|
||||
return WGPUStencilOperation::WGPUStencilOperation_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUShaderStageFlags toWGPUShaderStageFlag(ShaderStageFlagBit flag) {
|
||||
WGPUShaderStageFlags result = WGPUShaderStage::WGPUShaderStage_None;
|
||||
if (flag == ShaderStageFlagBit::NONE) {
|
||||
return WGPUShaderStage_None;
|
||||
}
|
||||
|
||||
if (flag == ShaderStageFlagBit::ALL || hasFlag(flag, ShaderStageFlagBit::VERTEX)) {
|
||||
result |= WGPUShaderStage::WGPUShaderStage_Vertex;
|
||||
}
|
||||
|
||||
if (flag == ShaderStageFlagBit::ALL || hasFlag(flag, ShaderStageFlagBit::FRAGMENT)) {
|
||||
result |= WGPUShaderStage::WGPUShaderStage_Fragment;
|
||||
}
|
||||
|
||||
if (flag == ShaderStageFlagBit::ALL || hasFlag(flag, ShaderStageFlagBit::COMPUTE)) {
|
||||
result |= WGPUShaderStage::WGPUShaderStage_Compute;
|
||||
}
|
||||
|
||||
if (result == WGPUShaderStage_None) {
|
||||
printf("Unsupport shader stage detected\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO_Zeqiang: more flexible strategy
|
||||
static uint32_t toWGPUSampleCount(SampleCount sampleCount) {
|
||||
return static_cast<uint32_t>(sampleCount);
|
||||
}
|
||||
|
||||
// NONE = 0,
|
||||
// TRANSFER_SRC = 0x1,
|
||||
// TRANSFER_DST = 0x2,
|
||||
// INDEX = 0x4,
|
||||
// VERTEX = 0x8,
|
||||
// UNIFORM = 0x10,
|
||||
// STORAGE = 0x20,
|
||||
// INDIRECT = 0x40,
|
||||
|
||||
static WGPUBufferUsageFlags toWGPUBufferUsage(BufferUsageBit usage) {
|
||||
if (usage == BufferUsageBit::NONE) {
|
||||
return WGPUBufferUsage::WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst;
|
||||
}
|
||||
|
||||
WGPUBufferUsageFlags res = WGPUBufferUsage::WGPUBufferUsage_None;
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::TRANSFER_SRC)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_CopySrc;
|
||||
}
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::TRANSFER_DST)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_CopyDst;
|
||||
}
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::INDEX)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_Index;
|
||||
}
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::VERTEX)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_Vertex;
|
||||
}
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::UNIFORM)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_Uniform;
|
||||
}
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::STORAGE)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_Storage;
|
||||
}
|
||||
|
||||
if (hasFlag(usage, BufferUsageBit::INDIRECT)) {
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_Indirect;
|
||||
}
|
||||
|
||||
// FIXME: depend on inputs but vertexbuffer was updated without COPY_DST.
|
||||
res |= WGPUBufferUsage::WGPUBufferUsage_CopyDst;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static WGPUColor toWGPUColor(const Color& color) {
|
||||
return WGPUColor{color.x, color.y, color.z, color.w};
|
||||
}
|
||||
|
||||
static WGPUVertexFormat toWGPUVertexFormat(Format format) {
|
||||
switch (format) {
|
||||
case Format::UNKNOWN:
|
||||
return WGPUVertexFormat_Undefined;
|
||||
case Format::RG8:
|
||||
return WGPUVertexFormat_Unorm8x2;
|
||||
case Format::RG8UI:
|
||||
return WGPUVertexFormat_Uint8x2;
|
||||
case Format::RG8I:
|
||||
return WGPUVertexFormat_Sint8x2;
|
||||
case Format::RG8SN:
|
||||
return WGPUVertexFormat_Snorm8x2;
|
||||
case Format::RGBA8:
|
||||
case Format::BGRA8:
|
||||
return WGPUVertexFormat_Unorm8x4;
|
||||
case Format::RGBA8UI:
|
||||
return WGPUVertexFormat_Uint8x4;
|
||||
case Format::SRGB8_A8:
|
||||
case Format::RGBA8I:
|
||||
return WGPUVertexFormat_Sint8x4;
|
||||
case Format::RGBA8SN:
|
||||
return WGPUVertexFormat_Snorm8x4;
|
||||
case Format::RG16UI:
|
||||
return WGPUVertexFormat_Uint16x2;
|
||||
case Format::RGBA16UI:
|
||||
return WGPUVertexFormat_Uint16x4;
|
||||
case Format::RG16I:
|
||||
return WGPUVertexFormat_Sint16x2;
|
||||
case Format::RGBA16I:
|
||||
return WGPUVertexFormat_Sint16x4;
|
||||
case Format::RG16F:
|
||||
return WGPUVertexFormat_Float16x2;
|
||||
case Format::RGBA16F:
|
||||
return WGPUVertexFormat_Float16x4;
|
||||
case Format::R32F:
|
||||
return WGPUVertexFormat_Float32;
|
||||
case Format::RG32F:
|
||||
return WGPUVertexFormat_Float32x2;
|
||||
case Format::RGB32F:
|
||||
return WGPUVertexFormat_Float32x3;
|
||||
case Format::RGBA32F:
|
||||
return WGPUVertexFormat_Float32x4;
|
||||
case Format::R32UI:
|
||||
return WGPUVertexFormat_Uint32;
|
||||
case Format::RG32UI:
|
||||
return WGPUVertexFormat_Uint32x2;
|
||||
case Format::RGB32UI:
|
||||
return WGPUVertexFormat_Uint32x3;
|
||||
case Format::RGBA32UI:
|
||||
return WGPUVertexFormat_Uint32x4;
|
||||
case Format::R32I:
|
||||
return WGPUVertexFormat_Sint32;
|
||||
case Format::RG32I:
|
||||
return WGPUVertexFormat_Sint32x2;
|
||||
case Format::RGB32I:
|
||||
return WGPUVertexFormat_Sint32x3;
|
||||
case Format::RGBA32I:
|
||||
return WGPUVertexFormat_Sint32x4;
|
||||
default:
|
||||
printf("usvf %d\n", static_cast<int>(format));
|
||||
return WGPUVertexFormat_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUPrimitiveTopology toWGPUPrimTopology(PrimitiveMode mode) {
|
||||
switch (mode) {
|
||||
case PrimitiveMode::POINT_LIST:
|
||||
return WGPUPrimitiveTopology_PointList;
|
||||
case PrimitiveMode::LINE_LIST:
|
||||
return WGPUPrimitiveTopology_LineList;
|
||||
case PrimitiveMode::LINE_STRIP:
|
||||
return WGPUPrimitiveTopology_LineStrip;
|
||||
case PrimitiveMode::TRIANGLE_LIST:
|
||||
return WGPUPrimitiveTopology_TriangleList;
|
||||
case PrimitiveMode::TRIANGLE_STRIP:
|
||||
return WGPUPrimitiveTopology_TriangleStrip;
|
||||
default:
|
||||
printf("Unsupport primitive topology.\n");
|
||||
return WGPUPrimitiveTopology_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUBlendOperation toWGPUBlendOperation(BlendOp blendOp) {
|
||||
switch (blendOp) {
|
||||
case BlendOp::ADD:
|
||||
return WGPUBlendOperation::WGPUBlendOperation_Add;
|
||||
case BlendOp::SUB:
|
||||
return WGPUBlendOperation::WGPUBlendOperation_Subtract;
|
||||
case BlendOp::REV_SUB:
|
||||
return WGPUBlendOperation::WGPUBlendOperation_ReverseSubtract;
|
||||
case BlendOp::MIN:
|
||||
return WGPUBlendOperation::WGPUBlendOperation_Min;
|
||||
case BlendOp::MAX:
|
||||
return WGPUBlendOperation::WGPUBlendOperation_Max;
|
||||
default:
|
||||
return WGPUBlendOperation::WGPUBlendOperation_Add;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUBlendFactor toWGPUBlendFactor(BlendFactor blendFactor) {
|
||||
switch (blendFactor) {
|
||||
case BlendFactor::ZERO:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_Zero;
|
||||
case BlendFactor::ONE:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_One;
|
||||
case BlendFactor::SRC_ALPHA:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_SrcAlpha;
|
||||
case BlendFactor::DST_ALPHA:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_DstAlpha;
|
||||
case BlendFactor::ONE_MINUS_SRC_ALPHA:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_OneMinusSrcAlpha;
|
||||
case BlendFactor::ONE_MINUS_DST_ALPHA:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_OneMinusDstAlpha;
|
||||
case BlendFactor::SRC_COLOR:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_Src;
|
||||
case BlendFactor::DST_COLOR:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_Dst;
|
||||
case BlendFactor::ONE_MINUS_SRC_COLOR:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_OneMinusSrc;
|
||||
case BlendFactor::ONE_MINUS_DST_COLOR:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_OneMinusDst;
|
||||
case BlendFactor::SRC_ALPHA_SATURATE:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_SrcAlphaSaturated;
|
||||
case BlendFactor::CONSTANT_COLOR:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_Constant;
|
||||
case BlendFactor::ONE_MINUS_CONSTANT_COLOR:
|
||||
return WGPUBlendFactor::WGPUBlendFactor_OneMinusConstant;
|
||||
default:
|
||||
printf("Unsupport blend factor config %d\n", static_cast<int>(blendFactor));
|
||||
return WGPUBlendFactor::WGPUBlendFactor_Force32;
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUFlags toWGPUColorWriteMask(ColorMask mask) {
|
||||
WGPUFlags result = WGPUColorWriteMask_None;
|
||||
if (mask == ColorMask::NONE) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mask & ColorMask::ALL || mask & ColorMask::R) result |= WGPUColorWriteMask::WGPUColorWriteMask_Red;
|
||||
if (mask & ColorMask::ALL || mask & ColorMask::G) result |= WGPUColorWriteMask::WGPUColorWriteMask_Green;
|
||||
if (mask & ColorMask::ALL || mask & ColorMask::B) result |= WGPUColorWriteMask::WGPUColorWriteMask_Blue;
|
||||
if (mask & ColorMask::ALL || mask & ColorMask::A) result |= WGPUColorWriteMask::WGPUColorWriteMask_Alpha;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ccstd::string getAdapterTypeName(WGPUAdapterType type) {
|
||||
switch (type) {
|
||||
case WGPUAdapterType_DiscreteGPU:
|
||||
return "WGPUAdapterType_DiscreteGPU";
|
||||
case WGPUAdapterType_IntegratedGPU:
|
||||
return "WGPUAdapterType_IntegratedGPU";
|
||||
case WGPUAdapterType_CPU:
|
||||
return "WGPUAdapterType_CPU";
|
||||
case WGPUAdapterType_Unknown:
|
||||
return "WGPUAdapterType_Unknown";
|
||||
default:
|
||||
return "unknown adapter by cc.gfx!";
|
||||
}
|
||||
}
|
||||
|
||||
static ccstd::string getBackendTypeName(WGPUBackendType type) {
|
||||
switch (type) {
|
||||
case WGPUBackendType_Null:
|
||||
return "WGPUBackendType_Null";
|
||||
case WGPUBackendType_WebGPU:
|
||||
return "WGPUBackendType_WebGPU";
|
||||
case WGPUBackendType_D3D11:
|
||||
return "WGPUBackendType_D3D11";
|
||||
case WGPUBackendType_D3D12:
|
||||
return "WGPUBackendType_D3D12";
|
||||
case WGPUBackendType_Metal:
|
||||
return "WGPUBackendType_Metal";
|
||||
case WGPUBackendType_Vulkan:
|
||||
return "WGPUBackendType_Vulkan";
|
||||
case WGPUBackendType_OpenGL:
|
||||
return "WGPUBackendType_OpenGL";
|
||||
case WGPUBackendType_OpenGLES:
|
||||
return "WGPUBackendType_OpenGLES";
|
||||
default:
|
||||
return "unknown backend by cc.gfx!";
|
||||
}
|
||||
}
|
||||
|
||||
class Texture;
|
||||
class CommandBuffer;
|
||||
// fromLevel and toLevel is included.
|
||||
void genMipMap(Texture* texture, uint8_t fromLevel, uint8_t levelCount, uint32_t baseLayer, CommandBuffer* cmdBuffer);
|
||||
|
||||
class DescriptorSet;
|
||||
class PipelineLayout;
|
||||
// descriptor set layout in descriptor set not consistent with the binding in pipeline layout.
|
||||
void createPipelineLayoutFallback(const ccstd::vector<DescriptorSet*>& descriptorSets, PipelineLayout* pipelineLayout, bool skipEmpty = false);
|
||||
|
||||
class Texture;
|
||||
class CommandBuffer;
|
||||
void clearRect(CommandBuffer* cmdBuffer, Texture* texture, const Rect& renderArea, const Color& color);
|
||||
void genMipMap(Texture* texture, uint8_t fromLevel, uint8_t levelCount, uint32_t baseLayer, CommandBuffer* cmdBuffer);
|
||||
|
||||
static constexpr WGPUColor defaultClearColor{0.2, 0.2, 0.2, 1.0};
|
||||
|
||||
static constexpr float defaultClearDepth = 1.0f;
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
64
cocos/renderer/gfx-wgpu/readme.md
Normal file
64
cocos/renderer/gfx-wgpu/readme.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# WebGPU on WASM by Emscripten
|
||||
|
||||
Based on Cocos Creator v3.6.2, emsdk 3.1.17.
|
||||
|
||||
WebGPU explainer: https://gpuweb.github.io/gpuweb/explainer/
|
||||
|
||||
## About WebGPU
|
||||
|
||||
#### What is WebGPU
|
||||
|
||||
distinguished from WebGL:
|
||||
>
|
||||
WebGPU is a proposed Web API to enable webpages to use the system’s GPU (Graphics Processing Unit) to perform computations and draw complex images that can be presented inside the page. This goal is similar to the WebGL family of APIs, but WebGPU enables access to more advanced features of GPUs. Whereas WebGL is mostly for drawing images but can be repurposed (with great effort) to do other kinds of computations, WebGPU has first-class support for performing general computations on the GPU.
|
||||
|
||||
#### Why WebGPU
|
||||
|
||||
There it is.
|
||||
|
||||
#### Why not write in typescript
|
||||
|
||||
Same to "why do it in c++ and then compile into wasm", in which way we can share other upper-level scheduler logic implementation instead of implement it again in typescript.
|
||||
|
||||
## Native Implementation
|
||||
|
||||
#### Compile
|
||||
|
||||
##### Environment
|
||||
|
||||
unix make is needed because of emscripten compile tool chain, so we have set up extra environment deployment on Windows:
|
||||
|
||||
[make](http://gnuwin32.sourceforge.net/packages/make.htm) [coreutils](http://gnuwin32.sourceforge.net/packages/coreutils.htm) [libiconv](http://gnuwin32.sourceforge.net/packages/libiconv.htm) [libintl](http://gnuwin32.sourceforge.net/packages/libintl.htm)
|
||||
|
||||
see details at [emscripten](https://emscripten.org/docs/getting_started/downloads.html).
|
||||
|
||||
after emscripten is deployed, type `emcc -v` in cmd/zsh, shown as below:
|
||||
```
|
||||
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.17 (fbc532773d84d2bd7da876275671970e792ad1cd)
|
||||
clang version 15.0.0 (https://github.com/llvm/llvm-project 17e4c217b66305e60657a48f10fe3c428c2fe4d2)
|
||||
Target: wasm32-unknown-emscripten
|
||||
Thread model: posix
|
||||
InstalledDir: D:\project\emsdk\upstream\bin
|
||||
```
|
||||
the output is slightly different from on mac.
|
||||
##### Custom
|
||||
|
||||
All the WGPU C++ files are in engine-native\cocos\renderer\gfx-wgpu. Modifications are applied only after manually compiling(next phrase), you need to copy the generated .js and .wasm to engine\native\external\emscripten\webgpu and engine\cocos\webgpu respectively and replace the original.
|
||||
|
||||
##### Compile
|
||||
|
||||
If any modification wants to applied in C++, cd to engine-native\cocos\renderer\gfx-wgpu and run:
|
||||
|
||||
`emcmake cmake .`
|
||||
|
||||
`emmake make`
|
||||
|
||||
this will generate the .js and .wasm file.
|
||||
|
||||
#### Implementation
|
||||
|
||||
##### C++ part
|
||||
|
||||
Same to other backends, all the graphics apis are included in `webgpu.h`.
|
||||
|
||||
TODO;
|
||||
38
cocos/renderer/gfx-wgpu/states/WGPUBufferBarrier.cpp
Normal file
38
cocos/renderer/gfx-wgpu/states/WGPUBufferBarrier.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
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 "WGPUBufferBarrier.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
WGPUBufferBarrier::WGPUBufferBarrier(const BufferBarrierInfo &info) : BufferBarrier(info) {
|
||||
}
|
||||
|
||||
ccstd::hash_t WGPUBufferBarrier::computeHash(const BufferBarrierInfo &info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
44
cocos/renderer/gfx-wgpu/states/WGPUBufferBarrier.h
Normal file
44
cocos/renderer/gfx-wgpu/states/WGPUBufferBarrier.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
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 <emscripten/val.h>
|
||||
#include "gfx-base/states/GFXBufferBarrier.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CC_DLL WGPUBufferBarrier : public BufferBarrier {
|
||||
public:
|
||||
explicit WGPUBufferBarrier(const BufferBarrierInfo &info);
|
||||
|
||||
static ccstd::hash_t computeHash(const BufferBarrierInfo &info);
|
||||
|
||||
// inline const GeneralBarrierInfo &getInfo() const { return _info; }
|
||||
// inline const ccstd::hash_t &getHash() const { return _hash; }
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
38
cocos/renderer/gfx-wgpu/states/WGPUGeneralBarrier.cpp
Normal file
38
cocos/renderer/gfx-wgpu/states/WGPUGeneralBarrier.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
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 "WGPUGeneralBarrier.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
WGPUGeneralBarrier::WGPUGeneralBarrier(const GeneralBarrierInfo &info) : GeneralBarrier(info) {
|
||||
}
|
||||
|
||||
ccstd::hash_t WGPUGeneralBarrier::computeHash(const GeneralBarrierInfo &info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
44
cocos/renderer/gfx-wgpu/states/WGPUGeneralBarrier.h
Normal file
44
cocos/renderer/gfx-wgpu/states/WGPUGeneralBarrier.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
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 <emscripten/val.h>
|
||||
#include "gfx-base/states/GFXGeneralBarrier.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CC_DLL WGPUGeneralBarrier : public GeneralBarrier {
|
||||
public:
|
||||
explicit WGPUGeneralBarrier(const GeneralBarrierInfo &info);
|
||||
|
||||
static ccstd::hash_t computeHash(const GeneralBarrierInfo &info);
|
||||
|
||||
// inline const GeneralBarrierInfo &getInfo() const { return _info; }
|
||||
// inline const ccstd::hash_t &getHash() const { return _hash; }
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
38
cocos/renderer/gfx-wgpu/states/WGPUTextureBarrier.cpp
Normal file
38
cocos/renderer/gfx-wgpu/states/WGPUTextureBarrier.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
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 "WGPUTextureBarrier.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
WGPUTextureBarrier::WGPUTextureBarrier(const TextureBarrierInfo &info) : TextureBarrier(info) {
|
||||
}
|
||||
|
||||
ccstd::hash_t WGPUTextureBarrier::computeHash(const TextureBarrierInfo &info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
41
cocos/renderer/gfx-wgpu/states/WGPUTextureBarrier.h
Normal file
41
cocos/renderer/gfx-wgpu/states/WGPUTextureBarrier.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/****************************************************************************
|
||||
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 <emscripten/val.h>
|
||||
#include "gfx-base/states/GFXTextureBarrier.h"
|
||||
|
||||
namespace cc {
|
||||
namespace gfx {
|
||||
|
||||
class CC_DLL WGPUTextureBarrier : public TextureBarrier {
|
||||
public:
|
||||
explicit WGPUTextureBarrier(const TextureBarrierInfo &info);
|
||||
|
||||
static ccstd::hash_t computeHash(const TextureBarrierInfo &info);
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace cc
|
||||
Reference in New Issue
Block a user