mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38:30 +09:00
DiligentRenderer now has DrawFromState() that: - reads the current MobileGL program SPIR-V and creates Diligent shaders - reads the current VAO enabled attributes and packs bound buffer data into an interleaved vertex buffer - creates a PSO with the matching input layout and primitive topology - supports DrawArrays, DrawElements, triangle-fan and line-loop expansion This is the first real front-end state wiring; it compiles and is used by GLFunctionsTable DrawArrays/DrawElements, but is not yet covered by a runtime state-driven test.
647 lines
25 KiB
C++
647 lines
25 KiB
C++
// MobileGL - MobileGL/MG_Backend/Diligent/Renderer/DiligentRenderer.cpp
|
|
// Copyright (c) 2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include "DiligentRenderer.h"
|
|
#include <RenderDevice.h>
|
|
#include <DeviceContext.h>
|
|
#include <Texture.h>
|
|
#include <Buffer.h>
|
|
#include <Shader.h>
|
|
#include <PipelineState.h>
|
|
#include <InputLayout.h>
|
|
|
|
#include <MG_State/GLState/Core.h>
|
|
#include <MG_State/GLState/ProgramState/ProgramObject.h>
|
|
#include <MG_State/GLState/VertexArrayState/VertexArrayObject.h>
|
|
#include <MG_State/GLState/BufferState/BufferObject.h>
|
|
#include <spirv_reflect.h>
|
|
|
|
#include <vector>
|
|
|
|
namespace MobileGL::MG_Backend::DiligentBackend {
|
|
namespace {
|
|
constexpr Uint32 kTriangleVertexCount = 3;
|
|
|
|
const char* GetTriangleVS() {
|
|
return R"(layout(location = 0) in vec2 Position;
|
|
void main()
|
|
{
|
|
gl_Position = vec4(Position, 0.0, 1.0);
|
|
}
|
|
)";
|
|
}
|
|
|
|
const char* GetTrianglePS() {
|
|
return R"(layout(location = 0) out vec4 Color;
|
|
void main()
|
|
{
|
|
Color = vec4(1.0, 0.0, 0.0, 1.0);
|
|
}
|
|
)";
|
|
}
|
|
|
|
struct TriangleVertex {
|
|
Float X;
|
|
Float Y;
|
|
};
|
|
|
|
SizeT GetDataTypeSize(DataType type) {
|
|
switch (type) {
|
|
case DataType::Int8:
|
|
case DataType::Uint8:
|
|
return 1;
|
|
case DataType::Int16:
|
|
case DataType::Uint16:
|
|
case DataType::Float16:
|
|
return 2;
|
|
case DataType::Int32:
|
|
case DataType::Uint32:
|
|
case DataType::Float32:
|
|
case DataType::Fixed32:
|
|
case DataType::Int2101010Rev:
|
|
case DataType::Uint2101010Rev:
|
|
return 4;
|
|
case DataType::Float64:
|
|
return 8;
|
|
default:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
::Diligent::VALUE_TYPE GetValueType(DataType type) {
|
|
switch (type) {
|
|
case DataType::Int8: return ::Diligent::VT_INT8;
|
|
case DataType::Uint8: return ::Diligent::VT_UINT8;
|
|
case DataType::Int16: return ::Diligent::VT_INT16;
|
|
case DataType::Uint16: return ::Diligent::VT_UINT16;
|
|
case DataType::Int32: return ::Diligent::VT_INT32;
|
|
case DataType::Uint32: return ::Diligent::VT_UINT32;
|
|
case DataType::Float16: return ::Diligent::VT_FLOAT16;
|
|
case DataType::Float32: return ::Diligent::VT_FLOAT32;
|
|
case DataType::Float64: return ::Diligent::VT_FLOAT64;
|
|
default: return ::Diligent::VT_FLOAT32;
|
|
}
|
|
}
|
|
|
|
Bool GetSpirvStage(const Vector<unsigned>& spv, ::Diligent::SHADER_TYPE& outStage) {
|
|
if (spv.empty()) {
|
|
return false;
|
|
}
|
|
SpvReflectShaderModule module{};
|
|
if (spvReflectCreateShaderModule(spv.size() * sizeof(unsigned), spv.data(), &module) !=
|
|
SPV_REFLECT_RESULT_SUCCESS) {
|
|
return false;
|
|
}
|
|
const SpvReflectShaderStageFlagBits stage = module.shader_stage;
|
|
spvReflectDestroyShaderModule(&module);
|
|
switch (stage) {
|
|
case SPV_REFLECT_SHADER_STAGE_VERTEX_BIT:
|
|
outStage = ::Diligent::SHADER_TYPE_VERTEX;
|
|
return true;
|
|
case SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT:
|
|
outStage = ::Diligent::SHADER_TYPE_PIXEL;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
DiligentRenderer::DiligentRenderer(::Diligent::IRenderDevice* device, ::Diligent::IDeviceContext* context)
|
|
: m_pDevice(device), m_pContext(context) {}
|
|
|
|
DiligentRenderer::~DiligentRenderer() {
|
|
m_pVertexBuffer.Release();
|
|
m_pPSO.Release();
|
|
m_pColorRTV.Release();
|
|
m_pColorTarget.Release();
|
|
}
|
|
|
|
Bool DiligentRenderer::Initialize(Uint32 width, Uint32 height) {
|
|
if (m_initialized) {
|
|
return true;
|
|
}
|
|
if (m_pDevice == nullptr || m_pContext == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
m_width = width > 0 ? width : 256;
|
|
m_height = height > 0 ? height : 256;
|
|
|
|
if (!CreateOffscreenTargets()) {
|
|
return false;
|
|
}
|
|
if (!CreatePipeline()) {
|
|
return false;
|
|
}
|
|
if (!CreateVertexBuffer()) {
|
|
return false;
|
|
}
|
|
|
|
m_initialized = true;
|
|
return true;
|
|
}
|
|
|
|
Bool DiligentRenderer::CreateOffscreenTargets() {
|
|
::Diligent::TextureDesc texDesc;
|
|
texDesc.Name = "MobileGL Diligent offscreen color target";
|
|
texDesc.Type = ::Diligent::RESOURCE_DIM_TEX_2D;
|
|
texDesc.Format = ::Diligent::TEX_FORMAT_RGBA8_UNORM;
|
|
texDesc.Width = m_width;
|
|
texDesc.Height = m_height;
|
|
texDesc.MipLevels = 1;
|
|
texDesc.BindFlags = ::Diligent::BIND_RENDER_TARGET | ::Diligent::BIND_SHADER_RESOURCE;
|
|
texDesc.Usage = ::Diligent::USAGE_DEFAULT;
|
|
|
|
::Diligent::RefCntAutoPtr<::Diligent::ITexture> pColorTarget;
|
|
m_pDevice->CreateTexture(texDesc, nullptr, &pColorTarget);
|
|
if (!pColorTarget) {
|
|
MGLOG_E("DiligentRenderer: failed to create offscreen color target");
|
|
return false;
|
|
}
|
|
|
|
m_pColorTarget = pColorTarget;
|
|
m_pColorRTV = m_pColorTarget->GetDefaultView(::Diligent::TEXTURE_VIEW_RENDER_TARGET);
|
|
if (!m_pColorRTV) {
|
|
MGLOG_E("DiligentRenderer: failed to get offscreen RTV");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Bool DiligentRenderer::CreatePipeline() {
|
|
::Diligent::GraphicsPipelineStateCreateInfo psoCI;
|
|
auto& psoDesc = psoCI.PSODesc;
|
|
auto& graphicsPipeline = psoCI.GraphicsPipeline;
|
|
|
|
psoDesc.PipelineType = ::Diligent::PIPELINE_TYPE_GRAPHICS;
|
|
psoDesc.Name = "MobileGL Diligent triangle PSO";
|
|
graphicsPipeline.NumRenderTargets = 1;
|
|
graphicsPipeline.RTVFormats[0] = ::Diligent::TEX_FORMAT_RGBA8_UNORM;
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
graphicsPipeline.RasterizerDesc.CullMode = ::Diligent::CULL_MODE_NONE;
|
|
graphicsPipeline.DepthStencilDesc.DepthEnable = false;
|
|
|
|
::Diligent::LayoutElement layoutElems[] = {
|
|
{0, 0, 2, ::Diligent::VT_FLOAT32},
|
|
};
|
|
graphicsPipeline.InputLayout.LayoutElements = layoutElems;
|
|
graphicsPipeline.InputLayout.NumElements = 1;
|
|
|
|
::Diligent::ShaderCreateInfo shaderCI;
|
|
shaderCI.SourceLanguage = ::Diligent::SHADER_SOURCE_LANGUAGE_GLSL;
|
|
shaderCI.EntryPoint = "main";
|
|
|
|
::Diligent::RefCntAutoPtr<::Diligent::IShader> pVS;
|
|
shaderCI.Desc = {"MobileGL Diligent triangle VS", ::Diligent::SHADER_TYPE_VERTEX, true};
|
|
shaderCI.Source = GetTriangleVS();
|
|
m_pDevice->CreateShader(shaderCI, &pVS);
|
|
if (!pVS) {
|
|
MGLOG_E("DiligentRenderer: failed to create vertex shader");
|
|
return false;
|
|
}
|
|
|
|
::Diligent::RefCntAutoPtr<::Diligent::IShader> pPS;
|
|
shaderCI.Desc = {"MobileGL Diligent triangle PS", ::Diligent::SHADER_TYPE_PIXEL, true};
|
|
shaderCI.Source = GetTrianglePS();
|
|
m_pDevice->CreateShader(shaderCI, &pPS);
|
|
if (!pPS) {
|
|
MGLOG_E("DiligentRenderer: failed to create pixel shader");
|
|
return false;
|
|
}
|
|
|
|
psoCI.pVS = pVS;
|
|
psoCI.pPS = pPS;
|
|
m_pDevice->CreateGraphicsPipelineState(psoCI, &m_pPSO);
|
|
if (!m_pPSO) {
|
|
MGLOG_E("DiligentRenderer: failed to create pipeline state");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Bool DiligentRenderer::CreateVertexBuffer() {
|
|
const TriangleVertex vertices[] = {
|
|
{-0.5f, -0.5f},
|
|
{ 0.5f, -0.5f},
|
|
{ 0.0f, 0.5f},
|
|
};
|
|
|
|
::Diligent::BufferDesc buffDesc;
|
|
buffDesc.Name = "MobileGL Diligent triangle vertex buffer";
|
|
buffDesc.BindFlags = ::Diligent::BIND_VERTEX_BUFFER;
|
|
buffDesc.Size = sizeof(vertices);
|
|
|
|
::Diligent::BufferData initialData;
|
|
initialData.pData = vertices;
|
|
initialData.DataSize = sizeof(vertices);
|
|
|
|
m_pDevice->CreateBuffer(buffDesc, &initialData, &m_pVertexBuffer);
|
|
if (!m_pVertexBuffer) {
|
|
MGLOG_E("DiligentRenderer: failed to create vertex buffer");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DiligentRenderer::Clear(Float r, Float g, Float b, Float a) {
|
|
if (!m_initialized || !m_pContext || !m_pColorRTV) {
|
|
return;
|
|
}
|
|
::Diligent::ITextureView* rtvs[] = {m_pColorRTV};
|
|
m_pContext->SetRenderTargets(1, rtvs, nullptr, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
const Float clearColor[] = {r, g, b, a};
|
|
m_pContext->ClearRenderTarget(m_pColorRTV, clearColor, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
}
|
|
|
|
void DiligentRenderer::DrawTriangle() {
|
|
if (!m_initialized || !m_pContext || !m_pPSO) {
|
|
return;
|
|
}
|
|
|
|
::Diligent::ITextureView* rtvs[] = {m_pColorRTV};
|
|
m_pContext->SetRenderTargets(1, rtvs, nullptr, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
|
|
::Diligent::Viewport viewport{0, 0, static_cast<Float>(m_width), static_cast<Float>(m_height), 0.0f, 1.0f};
|
|
m_pContext->SetViewports(1, &viewport, m_width, m_height);
|
|
|
|
::Diligent::IBuffer* pVBs[] = {m_pVertexBuffer};
|
|
m_pContext->SetVertexBuffers(0, 1, pVBs, nullptr,
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
|
|
::Diligent::SET_VERTEX_BUFFERS_FLAG_RESET);
|
|
|
|
m_pContext->SetPipelineState(m_pPSO);
|
|
::Diligent::DrawAttribs drawAttrs;
|
|
drawAttrs.NumVertices = kTriangleVertexCount;
|
|
drawAttrs.Flags = ::Diligent::DRAW_FLAG_VERIFY_ALL;
|
|
m_pContext->Draw(drawAttrs);
|
|
}
|
|
|
|
void DiligentRenderer::DrawVertices(const Float* vertices, Uint32 vertexCount) {
|
|
if (!m_initialized || !m_pContext || !m_pPSO || vertices == nullptr || vertexCount == 0) {
|
|
return;
|
|
}
|
|
|
|
const Uint64 dataSize = static_cast<Uint64>(vertexCount) * 2 * sizeof(Float);
|
|
if (dataSize > m_pVertexBuffer->GetDesc().Size) {
|
|
::Diligent::BufferDesc buffDesc;
|
|
buffDesc.Name = "MobileGL Diligent dynamic vertex buffer";
|
|
buffDesc.BindFlags = ::Diligent::BIND_VERTEX_BUFFER;
|
|
buffDesc.Size = dataSize;
|
|
|
|
::Diligent::BufferData initialData;
|
|
initialData.pData = vertices;
|
|
initialData.DataSize = static_cast<Uint32>(dataSize);
|
|
|
|
m_pDevice->CreateBuffer(buffDesc, &initialData, &m_pVertexBuffer);
|
|
if (!m_pVertexBuffer) {
|
|
MGLOG_E("DiligentRenderer: failed to create dynamic vertex buffer");
|
|
return;
|
|
}
|
|
} else {
|
|
m_pContext->UpdateBuffer(m_pVertexBuffer, 0, dataSize, vertices,
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
}
|
|
|
|
::Diligent::ITextureView* rtvs[] = {m_pColorRTV};
|
|
m_pContext->SetRenderTargets(1, rtvs, nullptr, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
|
|
::Diligent::Viewport viewport{0, 0, static_cast<Float>(m_width), static_cast<Float>(m_height), 0.0f, 1.0f};
|
|
m_pContext->SetViewports(1, &viewport, m_width, m_height);
|
|
|
|
::Diligent::IBuffer* pVBs[] = {m_pVertexBuffer};
|
|
m_pContext->SetVertexBuffers(0, 1, pVBs, nullptr,
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
|
|
::Diligent::SET_VERTEX_BUFFERS_FLAG_RESET);
|
|
|
|
m_pContext->SetPipelineState(m_pPSO);
|
|
::Diligent::DrawAttribs drawAttrs;
|
|
drawAttrs.NumVertices = vertexCount;
|
|
drawAttrs.Flags = ::Diligent::DRAW_FLAG_VERIFY_ALL;
|
|
m_pContext->Draw(drawAttrs);
|
|
}
|
|
|
|
void DiligentRenderer::DrawFromState(GLenum mode, GLint first, GLsizei count, GLenum type, const void* indices) {
|
|
if (!m_initialized || !m_pContext || MG_State::pGLContext == nullptr) {
|
|
return;
|
|
}
|
|
if (!CreatePipelineFromState(mode)) {
|
|
return;
|
|
}
|
|
if (!UploadVertexDataFromState(mode, first, count, type, indices)) {
|
|
return;
|
|
}
|
|
|
|
::Diligent::ITextureView* rtvs[] = {m_pColorRTV};
|
|
m_pContext->SetRenderTargets(1, rtvs, nullptr, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
|
|
::Diligent::Viewport viewport{0, 0, static_cast<Float>(m_width), static_cast<Float>(m_height), 0.0f, 1.0f};
|
|
m_pContext->SetViewports(1, &viewport, m_width, m_height);
|
|
|
|
::Diligent::IBuffer* pVBs[] = {m_pVertexBuffer};
|
|
m_pContext->SetVertexBuffers(0, 1, pVBs, nullptr,
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
|
|
::Diligent::SET_VERTEX_BUFFERS_FLAG_RESET);
|
|
m_pContext->SetPipelineState(m_pPSO);
|
|
|
|
::Diligent::DrawAttribs drawAttrs;
|
|
drawAttrs.NumVertices = m_lastDrawVertexCount;
|
|
drawAttrs.Flags = ::Diligent::DRAW_FLAG_VERIFY_ALL;
|
|
m_pContext->Draw(drawAttrs);
|
|
}
|
|
|
|
Bool DiligentRenderer::CreatePipelineFromState(GLenum mode) {
|
|
if (MG_State::pGLContext == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
const auto& program = MG_State::pGLContext->GetProgramForDraw();
|
|
if (!program || !program->GetSpirvStatus()) {
|
|
return false;
|
|
}
|
|
|
|
const auto& spirvs = program->GetGeneratedSpirv();
|
|
::Diligent::RefCntAutoPtr<::Diligent::IShader> pVS;
|
|
::Diligent::RefCntAutoPtr<::Diligent::IShader> pPS;
|
|
for (const auto& spv : spirvs) {
|
|
::Diligent::SHADER_TYPE stage = ::Diligent::SHADER_TYPE_UNKNOWN;
|
|
if (!GetSpirvStage(spv, stage)) {
|
|
continue;
|
|
}
|
|
::Diligent::ShaderCreateInfo shaderCI;
|
|
shaderCI.ByteCode = spv.data();
|
|
shaderCI.ByteCodeSize = spv.size() * sizeof(unsigned);
|
|
shaderCI.Desc = {"MobileGL Diligent state shader", stage, true};
|
|
::Diligent::RefCntAutoPtr<::Diligent::IShader> pShader;
|
|
m_pDevice->CreateShader(shaderCI, &pShader);
|
|
if (!pShader) {
|
|
MGLOG_E("DiligentRenderer: failed to create state shader");
|
|
return false;
|
|
}
|
|
if (stage == ::Diligent::SHADER_TYPE_VERTEX) {
|
|
pVS = pShader;
|
|
} else if (stage == ::Diligent::SHADER_TYPE_PIXEL) {
|
|
pPS = pShader;
|
|
}
|
|
}
|
|
if (!pVS || !pPS) {
|
|
MGLOG_W("DiligentRenderer: state program has no vertex/pixel SPIR-V");
|
|
return false;
|
|
}
|
|
|
|
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
|
|
const auto& attributes = vao.GetAllAttributes();
|
|
|
|
Vector<::Diligent::LayoutElement> layoutElements;
|
|
Vector<Uint32> activeAttribs;
|
|
for (Uint32 i = 0; i < vao.MAX_VERTEX_ATTRIBS; ++i) {
|
|
const auto& attr = attributes[i];
|
|
if (!attr.Enabled) {
|
|
continue;
|
|
}
|
|
::Diligent::LayoutElement elem{};
|
|
elem.InputIndex = i;
|
|
elem.BufferSlot = 0;
|
|
elem.NumComponents = static_cast<::Diligent::Uint32>(attr.Size);
|
|
elem.ValueType = GetValueType(attr.Type);
|
|
elem.IsNormalized = attr.Normalized;
|
|
activeAttribs.push_back(i);
|
|
layoutElements.push_back(elem);
|
|
}
|
|
if (layoutElements.empty()) {
|
|
MGLOG_W("DiligentRenderer: no enabled vertex attributes");
|
|
return false;
|
|
}
|
|
|
|
::Diligent::GraphicsPipelineStateCreateInfo psoCI;
|
|
auto& psoDesc = psoCI.PSODesc;
|
|
auto& graphicsPipeline = psoCI.GraphicsPipeline;
|
|
psoDesc.PipelineType = ::Diligent::PIPELINE_TYPE_GRAPHICS;
|
|
psoDesc.Name = "MobileGL Diligent state PSO";
|
|
graphicsPipeline.NumRenderTargets = 1;
|
|
graphicsPipeline.RTVFormats[0] = ::Diligent::TEX_FORMAT_RGBA8_UNORM;
|
|
switch (mode) {
|
|
case GL_POINTS:
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_POINT_LIST;
|
|
break;
|
|
case GL_LINES:
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_LINE_LIST;
|
|
break;
|
|
case GL_LINE_STRIP:
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
|
break;
|
|
case GL_TRIANGLES:
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
break;
|
|
case GL_TRIANGLE_STRIP:
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
|
break;
|
|
default:
|
|
// GL_TRIANGLE_FAN and GL_LINE_LOOP are emulated in UploadVertexData.
|
|
graphicsPipeline.PrimitiveTopology = ::Diligent::PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
break;
|
|
}
|
|
graphicsPipeline.RasterizerDesc.CullMode = ::Diligent::CULL_MODE_NONE;
|
|
graphicsPipeline.DepthStencilDesc.DepthEnable = false;
|
|
graphicsPipeline.InputLayout.LayoutElements = layoutElements.data();
|
|
graphicsPipeline.InputLayout.NumElements = static_cast<::Diligent::Uint32>(layoutElements.size());
|
|
|
|
psoCI.pVS = pVS;
|
|
psoCI.pPS = pPS;
|
|
m_pDevice->CreateGraphicsPipelineState(psoCI, &m_pPSO);
|
|
if (!m_pPSO) {
|
|
MGLOG_E("DiligentRenderer: failed to create state pipeline");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Bool DiligentRenderer::UploadVertexDataFromState(GLenum mode, GLint first, GLsizei count, GLenum type,
|
|
const void* indices) {
|
|
if (MG_State::pGLContext == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
|
|
const auto& attributes = vao.GetAllAttributes();
|
|
|
|
Vector<Uint32> activeAttribs;
|
|
for (Uint32 i = 0; i < vao.MAX_VERTEX_ATTRIBS; ++i) {
|
|
if (attributes[i].Enabled) {
|
|
activeAttribs.push_back(i);
|
|
}
|
|
}
|
|
if (activeAttribs.empty()) {
|
|
return false;
|
|
}
|
|
|
|
// Resolve the vertex index list (DrawArrays first..first+count or
|
|
// DrawElements index buffer/client memory).
|
|
Vector<Uint32> indicesData;
|
|
const Uint32 vertexCount = static_cast<Uint32>(count);
|
|
if (mode == GL_TRIANGLE_FAN) {
|
|
// Expand a triangle fan into a triangle list.
|
|
indicesData.reserve((vertexCount - 2) * 3);
|
|
for (Uint32 i = 1; i + 1 < vertexCount; ++i) {
|
|
indicesData.push_back(0);
|
|
indicesData.push_back(i);
|
|
indicesData.push_back(i + 1);
|
|
}
|
|
} else if (mode == GL_LINE_LOOP) {
|
|
indicesData.reserve(vertexCount + 1);
|
|
for (Uint32 i = 0; i < vertexCount; ++i) {
|
|
indicesData.push_back(i);
|
|
}
|
|
if (vertexCount > 0) {
|
|
indicesData.push_back(0);
|
|
}
|
|
} else if (type != 0 || indices != nullptr) {
|
|
// DrawElements path.
|
|
const auto& indexSlot = vao.GetIndexBufferBindingSlot();
|
|
const auto& indexBuffer = indexSlot.GetBoundObject();
|
|
const Uint8* indexBase = nullptr;
|
|
if (indexBuffer) {
|
|
indexBuffer->SyncPersistentMappedRange();
|
|
indexBase = indexBuffer->MappedData();
|
|
if (indexBase == nullptr) {
|
|
return false;
|
|
}
|
|
indexBase += reinterpret_cast<SizeT>(indices);
|
|
} else {
|
|
indexBase = static_cast<const Uint8*>(indices);
|
|
if (indexBase == nullptr) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const SizeT indexSize = GetDataTypeSize(
|
|
type == GL_UNSIGNED_BYTE ? DataType::Uint8 :
|
|
type == GL_UNSIGNED_SHORT ? DataType::Uint16 : DataType::Uint32);
|
|
indicesData.reserve(vertexCount);
|
|
for (Uint32 i = 0; i < vertexCount; ++i) {
|
|
if (indexSize == 1) {
|
|
indicesData.push_back(indexBase[i]);
|
|
} else if (indexSize == 2) {
|
|
indicesData.push_back(reinterpret_cast<const Uint16*>(indexBase)[i]);
|
|
} else {
|
|
indicesData.push_back(reinterpret_cast<const Uint32*>(indexBase)[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
const Uint32 drawVertexCount = indicesData.empty() ? vertexCount : static_cast<Uint32>(indicesData.size());
|
|
if (drawVertexCount == 0) {
|
|
return false;
|
|
}
|
|
|
|
// Pack enabled attributes into a single interleaved vertex buffer.
|
|
SizeT vertexStride = 0;
|
|
for (Uint32 attrIndex : activeAttribs) {
|
|
vertexStride += GetDataTypeSize(attributes[attrIndex].Type) * static_cast<SizeT>(attributes[attrIndex].Size);
|
|
}
|
|
|
|
Vector<Uint8> vertexData(static_cast<SizeT>(drawVertexCount) * vertexStride);
|
|
for (Uint32 vi = 0; vi < drawVertexCount; ++vi) {
|
|
const Uint32 srcIndex = indicesData.empty() ? (static_cast<Uint32>(first) + vi) : indicesData[vi];
|
|
Uint8* dst = vertexData.data() + static_cast<SizeT>(vi) * vertexStride;
|
|
for (Uint32 attrIndex : activeAttribs) {
|
|
const auto& attr = attributes[attrIndex];
|
|
if (!attr.Buffer) {
|
|
return false;
|
|
}
|
|
attr.Buffer->SyncPersistentMappedRange();
|
|
const Uint8* src = attr.Buffer->MappedData();
|
|
if (src == nullptr) {
|
|
return false;
|
|
}
|
|
const SizeT elemSize = GetDataTypeSize(attr.Type) * static_cast<SizeT>(attr.Size);
|
|
const SizeT srcOffset = attr.Offset + static_cast<SizeT>(srcIndex) * static_cast<SizeT>(attr.Stride);
|
|
if (srcOffset + elemSize > attr.Buffer->GetSize()) {
|
|
return false;
|
|
}
|
|
std::memcpy(dst, src + srcOffset, elemSize);
|
|
dst += elemSize;
|
|
}
|
|
}
|
|
|
|
if (!m_pVertexBuffer || m_pVertexBuffer->GetDesc().Size < vertexData.size()) {
|
|
::Diligent::BufferDesc buffDesc;
|
|
buffDesc.Name = "MobileGL Diligent state vertex buffer";
|
|
buffDesc.BindFlags = ::Diligent::BIND_VERTEX_BUFFER;
|
|
buffDesc.Size = vertexData.size();
|
|
::Diligent::BufferData initialData;
|
|
initialData.pData = vertexData.data();
|
|
initialData.DataSize = static_cast<::Diligent::Uint32>(vertexData.size());
|
|
m_pDevice->CreateBuffer(buffDesc, &initialData, &m_pVertexBuffer);
|
|
if (!m_pVertexBuffer) {
|
|
return false;
|
|
}
|
|
} else {
|
|
m_pContext->UpdateBuffer(m_pVertexBuffer, 0, vertexData.size(), vertexData.data(),
|
|
::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
|
|
}
|
|
m_lastDrawVertexCount = drawVertexCount;
|
|
return true;
|
|
}
|
|
|
|
void DiligentRenderer::ReadPixels(Uint32 x, Uint32 y, Uint32 width, Uint32 height, void* pixels) {
|
|
if (!m_initialized || !m_pContext || !m_pColorTarget || pixels == nullptr) {
|
|
return;
|
|
}
|
|
|
|
::Diligent::TextureDesc stagingDesc;
|
|
stagingDesc.Name = "MobileGL Diligent staging readback";
|
|
stagingDesc.Type = ::Diligent::RESOURCE_DIM_TEX_2D;
|
|
stagingDesc.Format = ::Diligent::TEX_FORMAT_RGBA8_UNORM;
|
|
stagingDesc.Width = m_width;
|
|
stagingDesc.Height = m_height;
|
|
stagingDesc.MipLevels = 1;
|
|
stagingDesc.Usage = ::Diligent::USAGE_STAGING;
|
|
stagingDesc.CPUAccessFlags = ::Diligent::CPU_ACCESS_READ;
|
|
|
|
::Diligent::RefCntAutoPtr<::Diligent::ITexture> pStaging;
|
|
m_pDevice->CreateTexture(stagingDesc, nullptr, &pStaging);
|
|
if (!pStaging) {
|
|
MGLOG_E("DiligentRenderer: failed to create staging texture");
|
|
return;
|
|
}
|
|
|
|
::Diligent::CopyTextureAttribs copyAttribs{
|
|
m_pColorTarget, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION,
|
|
pStaging, ::Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION};
|
|
copyAttribs.SrcMipLevel = 0;
|
|
copyAttribs.DstMipLevel = 0;
|
|
copyAttribs.SrcSlice = 0;
|
|
copyAttribs.DstSlice = 0;
|
|
m_pContext->CopyTexture(copyAttribs);
|
|
m_pContext->WaitForIdle();
|
|
|
|
::Diligent::MappedTextureSubresource mapped;
|
|
m_pContext->MapTextureSubresource(pStaging, 0, 0, ::Diligent::MAP_READ,
|
|
::Diligent::MAP_FLAG_DO_NOT_WAIT, nullptr, mapped);
|
|
if (mapped.pData == nullptr) {
|
|
MGLOG_E("DiligentRenderer: failed to map staging texture");
|
|
return;
|
|
}
|
|
|
|
const Uint8* srcBase = static_cast<const Uint8*>(mapped.pData) + y * mapped.Stride + x * 4;
|
|
Uint8* dst = static_cast<Uint8*>(pixels);
|
|
for (Uint32 row = 0; row < height; ++row) {
|
|
std::memcpy(dst + row * width * 4, srcBase + row * mapped.Stride, width * 4);
|
|
}
|
|
|
|
m_pContext->UnmapTextureSubresource(pStaging, 0, 0);
|
|
}
|
|
|
|
void DiligentRenderer::Present() {
|
|
// Offscreen renderer: nothing to present yet.
|
|
if (m_pContext) {
|
|
m_pContext->Flush();
|
|
}
|
|
}
|
|
} // namespace MobileGL::MG_Backend::DiligentBackend
|