Upload models to GPU before rendering (#272)

This commit is contained in:
Anders Jenbo 2025-06-10 06:34:49 +02:00 committed by GitHub
parent 9ebeda5c0e
commit c8b8035de8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 578 additions and 436 deletions

View File

@ -192,6 +192,91 @@ Uint32 OpenGL15Renderer::GetTextureId(IDirect3DRMTexture* iTexture)
return (Uint32) (m_textures.size() - 1);
}
GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup)
{
GLMeshCacheEntry cache{&meshGroup, meshGroup.version};
cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT;
std::vector<D3DRMVERTEX> vertices;
if (cache.flat) {
FlattenSurfaces(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
meshGroup.texture != nullptr,
vertices,
cache.indices
);
}
else {
vertices.assign(meshGroup.vertices.begin(), meshGroup.vertices.end());
cache.indices.assign(meshGroup.indices.begin(), meshGroup.indices.end());
}
cache.texcoords.resize(vertices.size());
std::transform(vertices.begin(), vertices.end(), cache.texcoords.begin(), [](const D3DRMVERTEX& v) {
return v.texCoord;
});
cache.positions.resize(vertices.size());
std::transform(vertices.begin(), vertices.end(), cache.positions.begin(), [](const D3DRMVERTEX& v) {
return v.position;
});
cache.normals.resize(vertices.size());
std::transform(vertices.begin(), vertices.end(), cache.normals.begin(), [](const D3DRMVERTEX& v) {
return v.normal;
});
return cache;
}
struct GLMeshDestroyContext {
OpenGL15Renderer* renderer;
Uint32 id;
};
void OpenGL15Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new GLMeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<GLMeshDestroyContext*>(arg);
ctx->renderer->m_meshs[ctx->id].meshGroup = nullptr;
delete ctx;
},
ctx
);
}
Uint32 OpenGL15Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
{
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
cache = std::move(GLUploadMesh(*meshGroup));
}
return i;
}
}
auto newCache = GLUploadMesh(*meshGroup);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (!cache.meshGroup) {
cache = std::move(newCache);
AddMeshDestroyCallback(i, mesh);
return i;
}
}
m_meshs.push_back(std::move(newCache));
AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh);
return (Uint32) (m_meshs.size() - 1);
}
DWORD OpenGL15Renderer::GetWidth()
{
return m_width;
@ -306,10 +391,7 @@ HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
}
void OpenGL15Renderer::SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -323,47 +405,9 @@ void OpenGL15Renderer::SubmitDraw(
glLoadMatrixf(&mvMatrix[0][0]);
glEnable(GL_NORMALIZE);
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
if (appearance.flat) {
glShadeModel(GL_FLAT);
// FIXME move this to a one time mesh upload stage
FlattenSurfaces(
vertices,
vertexCount,
indices,
indexCount,
appearance.textureId != NO_TEXTURE_ID,
newVertices,
newIndices
);
}
else {
glShadeModel(GL_SMOOTH);
newVertices.assign(vertices, vertices + vertexCount);
newIndices.assign(indices, indices + indexCount);
}
// Bind texture if present
std::vector<TexCoord> texcoords;
if (appearance.textureId != NO_TEXTURE_ID) {
auto& tex = m_textures[appearance.textureId];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
texcoords.resize(newVertices.size());
std::transform(newVertices.begin(), newVertices.end(), texcoords.begin(), [](const D3DRMVERTEX& v) {
return v.texCoord;
});
}
else {
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
float shininess = appearance.shininess;
float shininess = appearance.shininess * m_shininessFactor;
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
if (shininess != 0.0f) {
GLfloat whiteSpec[] = {shininess, shininess, shininess, shininess};
@ -374,29 +418,36 @@ void OpenGL15Renderer::SubmitDraw(
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
}
std::vector<D3DVECTOR> positions;
positions.resize(newVertices.size());
std::transform(newVertices.begin(), newVertices.end(), positions.begin(), [](const D3DRMVERTEX& v) {
return v.position;
});
std::vector<D3DVECTOR> normals;
normals.resize(newVertices.size());
std::transform(newVertices.begin(), newVertices.end(), normals.begin(), [](const D3DRMVERTEX& v) {
return v.normal;
});
auto& mesh = m_meshs[meshId];
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, positions.data());
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals.data());
if (appearance.textureId != NO_TEXTURE_ID) {
glTexCoordPointer(2, GL_FLOAT, 0, texcoords.data());
if (mesh.flat) {
glShadeModel(GL_FLAT);
}
else {
glShadeModel(GL_SMOOTH);
}
// Bind texture if present
if (appearance.textureId != NO_TEXTURE_ID) {
auto& tex = m_textures[appearance.textureId];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data());
}
else {
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data());
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, mesh.normals.data());
// Draw triangles
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(newIndices.size()), GL_UNSIGNED_INT, newIndices.data());
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, mesh.indices.data());
glPopMatrix();
}

View File

@ -91,76 +91,6 @@ struct ScopedShader {
void release() { ptr = nullptr; }
};
SDL_GPUTexture* CreateTextureFromSurface(
SDL_GPUDevice* device,
SDL_GPUTransferBuffer* transferBuffer,
SDL_Surface* surface
)
{
ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888)};
if (!surf.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError());
return nullptr;
}
const Uint32 dataSize = surf.ptr->pitch * surf.ptr->h;
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
textureInfo.width = surf.ptr->w;
textureInfo.height = surf.ptr->h;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
ScopedTexture texture{device, SDL_CreateGPUTexture(device, &textureInfo)};
if (!texture.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture (%s)", SDL_GetError());
return nullptr;
}
void* transferData = SDL_MapGPUTransferBuffer(device, transferBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer (%s)", SDL_GetError());
return nullptr;
}
memcpy(transferData, surf.ptr->pixels, dataSize);
SDL_UnmapGPUTransferBuffer(device, transferBuffer);
SDL_GPUTextureTransferInfo transferRegionInfo = {};
transferRegionInfo.transfer_buffer = transferBuffer;
SDL_GPUTextureRegion textureRegion = {};
textureRegion.texture = texture.ptr;
textureRegion.w = surf.ptr->w;
textureRegion.h = surf.ptr->h;
textureRegion.d = 1;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(device);
if (!cmdbuf) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_AcquireGPUCommandBuffer in CreateTextureFromSurface failed (%s)",
SDL_GetError()
);
return nullptr;
}
SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_UploadToGPUTexture(pass, &transferRegionInfo, &textureRegion, false);
SDL_EndGPUCopyPass(pass);
if (!SDL_SubmitGPUCommandBuffer(cmdbuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer (%s)", SDL_GetError());
return nullptr;
}
auto texptr = texture.ptr;
// Release texture ownership so caller can manage it safely
texture.release();
return texptr;
}
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device, bool depthWrite)
{
const SDL_GPUShaderCreateInfo* vertexCreateInfo =
@ -325,24 +255,6 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
return nullptr;
}
SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ABGR8888);
if (!dummySurface) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError());
return nullptr;
}
if (!SDL_LockSurface(dummySurface)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to lock surface: %s", SDL_GetError());
SDL_DestroySurface(dummySurface);
return nullptr;
}
((Uint32*) dummySurface->pixels)[0] = 0xFFFFFFFF;
ScopedTexture dummyTexture{device.ptr, CreateTextureFromSurface(device.ptr, uploadBuffer.ptr, dummySurface)};
SDL_DestroySurface(dummySurface);
if (!dummyTexture.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create texture from surface");
return nullptr;
}
SDL_GPUSamplerCreateInfo samplerInfo = {};
samplerInfo.min_filter = SDL_GPU_FILTER_LINEAR;
samplerInfo.mag_filter = SDL_GPU_FILTER_LINEAR;
@ -364,7 +276,6 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
transparentPipeline.ptr,
transferTexture.ptr,
depthTexture.ptr,
dummyTexture.ptr,
sampler.ptr,
uploadBuffer.ptr,
downloadBuffer.ptr
@ -376,7 +287,6 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
transparentPipeline.release();
transferTexture.release();
depthTexture.release();
dummyTexture.release();
sampler.release();
uploadBuffer.release();
downloadBuffer.release();
@ -392,15 +302,29 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUTexture* dummyTexture,
SDL_GPUSampler* sampler,
SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer
)
: m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline),
m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture),
m_dummyTexture(dummyTexture), m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer)
m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer)
{
SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ABGR8888);
if (!dummySurface) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError());
return;
}
if (!SDL_LockSurface(dummySurface)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to lock surface: %s", SDL_GetError());
SDL_DestroySurface(dummySurface);
return;
}
((Uint32*) dummySurface->pixels)[0] = 0xFFFFFFFF;
SDL_UnlockSurface(dummySurface);
m_dummyTexture = CreateTextureFromSurface(dummySurface);
SDL_DestroySurface(dummySurface);
}
Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer()
@ -412,10 +336,12 @@ Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer()
SDL_ReleaseGPUSampler(m_device, m_sampler);
SDL_ReleaseGPUTexture(m_device, m_dummyTexture);
SDL_ReleaseGPUTexture(m_device, m_depthTexture);
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
SDL_ReleaseGPUTexture(m_device, m_transferTexture);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline);
if (m_uploadFence) {
SDL_ReleaseGPUFence(m_device, m_uploadFence);
}
SDL_DestroyGPUDevice(m_device);
}
@ -436,6 +362,19 @@ void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D
memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D));
}
void Direct3DRMSDL3GPURenderer::WaitForPendingUpload()
{
if (!m_uploadFence) {
return;
}
bool success = SDL_WaitForGPUFences(m_device, true, &m_uploadFence, 1);
SDL_ReleaseGPUFence(m_device, m_uploadFence);
m_uploadFence = nullptr;
if (!success) {
return;
}
}
struct SDLTextureDestroyContext {
Direct3DRMSDL3GPURenderer* renderer;
Uint32 id;
@ -459,6 +398,69 @@ void Direct3DRMSDL3GPURenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRM
);
}
SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* surface)
{
ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888)};
if (!surf.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError());
return nullptr;
}
const Uint32 dataSize = surf.ptr->pitch * surf.ptr->h;
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
textureInfo.width = surf.ptr->w;
textureInfo.height = surf.ptr->h;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
ScopedTexture texture{m_device, SDL_CreateGPUTexture(m_device, &textureInfo)};
if (!texture.ptr) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture (%s)", SDL_GetError());
return nullptr;
}
SDL_GPUTransferBuffer* transferBuffer = GetUploadBuffer(dataSize);
void* transferData = SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer (%s)", SDL_GetError());
return nullptr;
}
memcpy(transferData, surf.ptr->pixels, dataSize);
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
SDL_GPUTextureTransferInfo transferRegionInfo = {};
transferRegionInfo.transfer_buffer = transferBuffer;
SDL_GPUTextureRegion textureRegion = {};
textureRegion.texture = texture.ptr;
textureRegion.w = surf.ptr->w;
textureRegion.h = surf.ptr->h;
textureRegion.d = 1;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_AcquireGPUCommandBuffer in CreateTextureFromSurface failed (%s)",
SDL_GetError()
);
return nullptr;
}
SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_UploadToGPUTexture(pass, &transferRegionInfo, &textureRegion, false);
SDL_EndGPUCopyPass(pass);
m_uploadFence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
auto texptr = texture.ptr;
// Release texture ownership so caller can manage it safely
texture.release();
return texptr;
}
Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture)
{
auto texture = static_cast<Direct3DRMTextureImpl*>(iTexture);
@ -470,7 +472,7 @@ Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture)
if (tex.texture == texture) {
if (tex.version != texture->m_version) {
SDL_ReleaseGPUTexture(m_device, tex.gpuTexture);
tex.gpuTexture = CreateTextureFromSurface(m_device, GetUploadBuffer(surf->w * surf->h * 4), surf);
tex.gpuTexture = CreateTextureFromSurface(surf);
if (!tex.gpuTexture) {
return NO_TEXTURE_ID;
}
@ -480,7 +482,7 @@ Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture)
}
}
SDL_GPUTexture* newTex = CreateTextureFromSurface(m_device, GetUploadBuffer(surf->w * surf->h * 4), surf);
SDL_GPUTexture* newTex = CreateTextureFromSurface(surf);
if (!newTex) {
return NO_TEXTURE_ID;
}
@ -499,6 +501,123 @@ Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* iTexture)
return (Uint32) (m_textures.size() - 1);
}
SDL3MeshCache Direct3DRMSDL3GPURenderer::UploadMesh(const MeshGroup& meshGroup)
{
std::vector<D3DRMVERTEX> flatVertices;
if (meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT) {
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
FlattenSurfaces(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
meshGroup.texture != nullptr,
newVertices,
newIndices
);
for (DWORD& index : newIndices) {
flatVertices.push_back(newVertices[index]);
}
}
else {
// TODO handle indexed verticies on GPU
for (int i = 0; i < meshGroup.indices.size(); ++i) {
flatVertices.push_back(meshGroup.vertices[meshGroup.indices[i]]);
}
}
SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
bufferCreateInfo.size = sizeof(D3DRMVERTEX) * flatVertices.size();
SDL_GPUBuffer* vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer failed (%s)", SDL_GetError());
}
SDL_GPUTransferBuffer* uploadBuffer = GetUploadBuffer(sizeof(D3DRMVERTEX) * flatVertices.size());
if (!uploadBuffer) {
return {};
}
D3DRMVERTEX* transferData = (D3DRMVERTEX*) SDL_MapGPUTransferBuffer(m_device, uploadBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer returned NULL buffer (%s)", SDL_GetError());
return {};
}
memcpy(transferData, flatVertices.data(), sizeof(D3DRMVERTEX) * flatVertices.size());
SDL_UnmapGPUTransferBuffer(m_device, uploadBuffer);
SDL_GPUTransferBufferLocation transferLocation = {};
transferLocation.transfer_buffer = uploadBuffer;
SDL_GPUBufferRegion bufferRegion = {};
bufferRegion.buffer = vertexBuffer;
bufferRegion.size = static_cast<Uint32>(sizeof(D3DRMVERTEX) * flatVertices.size());
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in SubmitDraw failed (%s)", SDL_GetError());
return {};
}
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
m_uploadFence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
return {&meshGroup, meshGroup.version, vertexBuffer, flatVertices.size()};
}
struct SDLMeshDestroyContext {
Direct3DRMSDL3GPURenderer* renderer;
Uint32 id;
};
void Direct3DRMSDL3GPURenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new SDLMeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<SDLMeshDestroyContext*>(arg);
auto& cache = ctx->renderer->m_meshs[ctx->id];
SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer);
cache.meshGroup = nullptr;
delete ctx;
},
ctx
);
}
Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
{
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer);
cache = std::move(UploadMesh(*meshGroup));
}
return i;
}
}
auto newCache = UploadMesh(*meshGroup);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (!cache.meshGroup) {
cache = std::move(newCache);
AddMeshDestroyCallback(i, mesh);
return i;
}
}
m_meshs.push_back(std::move(newCache));
AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh);
return (Uint32) (m_meshs.size() - 1);
}
DWORD Direct3DRMSDL3GPURenderer::GetWidth()
{
return m_width;
@ -527,42 +646,6 @@ const char* Direct3DRMSDL3GPURenderer::GetName()
return "SDL3 GPU HAL";
}
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
if (!DDBackBuffer) {
return DDERR_GENERIC;
}
memcpy(&m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D));
// Clear color and depth targets
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.clear_color = {0, 0, 0, 0};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.clear_depth = 0.0f;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in BeginFrame failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_EndGPURenderPass(renderPass);
if (!SDL_SubmitGPUCommandBuffer(cmdbuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
return DD_OK;
}
void PackNormalMatrix(const Matrix3x3& normalMatrix3x3, D3DRMMATRIX4D& packedNormalMatrix4x4)
{
for (int row = 0; row < 3; ++row) {
@ -578,6 +661,7 @@ void PackNormalMatrix(const Matrix3x3& normalMatrix3x3, D3DRMMATRIX4D& packedNor
SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
{
WaitForPendingUpload();
if (m_uploadBufferSize < size) {
SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer);
@ -599,140 +683,75 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
return m_uploadBuffer;
}
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
if (!DDBackBuffer) {
return DDERR_GENERIC;
}
memcpy(&m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D));
// Clear color and depth targets
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.clear_color = {0, 0, 0, 0};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.clear_depth = 0.0f;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!m_cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in BeginFrame failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
m_renderPass = SDL_BeginGPURenderPass(m_cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_BindGPUGraphicsPipeline(m_renderPass, m_opaquePipeline);
return DD_OK;
}
void Direct3DRMSDL3GPURenderer::SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
{
// TODO only switch piplinen after all opaque's have been rendered
SDL_BindGPUGraphicsPipeline(m_renderPass, appearance.color.a == 255 ? m_opaquePipeline : m_transparentPipeline);
D3DRMMATRIX4D worldViewMatrix;
MultiplyMatrix(worldViewMatrix, worldMatrix, m_viewMatrix);
memcpy(&m_uniforms.worldViewMatrix, worldViewMatrix, sizeof(D3DRMMATRIX4D));
PackNormalMatrix(normalMatrix, m_uniforms.normalMatrix);
m_fragmentShadingData.color = appearance.color;
m_fragmentShadingData.shininess = appearance.shininess;
m_fragmentShadingData.shininess = appearance.shininess * m_shininessFactor;
bool useTexture = appearance.textureId != NO_TEXTURE_ID;
m_fragmentShadingData.useTexture = appearance.textureId != NO_TEXTURE_ID;
std::vector<D3DRMVERTEX> flatVertices;
if (appearance.flat) {
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
// FIXME move this to a one time mesh upload stage
FlattenSurfaces(
vertices,
vertexCount,
indices,
indexCount,
appearance.textureId != NO_TEXTURE_ID,
newVertices,
newIndices
);
for (DWORD& index : newIndices) {
flatVertices.push_back(newVertices[index]);
}
}
else {
// TODO handle indexed verticies on GPU
for (int i = 0; i < indexCount; ++i) {
flatVertices.push_back(vertices[indices[i]]);
}
}
if (flatVertices.size() > m_vertexBufferCount) {
if (m_vertexBuffer) {
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
}
SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
bufferCreateInfo.size = static_cast<Uint32>(sizeof(D3DRMVERTEX) * flatVertices.size());
m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!m_vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer failed (%s)", SDL_GetError());
}
m_vertexBufferCount = flatVertices.size();
}
m_vertexCount = flatVertices.size();
SDL_GPUTransferBuffer* uploadBuffer = GetUploadBuffer(sizeof(D3DRMVERTEX) * m_vertexCount);
if (!uploadBuffer) {
return;
}
D3DRMVERTEX* transferData = (D3DRMVERTEX*) SDL_MapGPUTransferBuffer(m_device, uploadBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer returned NULL buffer (%s)", SDL_GetError());
return;
}
memcpy(transferData, flatVertices.data(), m_vertexCount * sizeof(D3DRMVERTEX));
SDL_UnmapGPUTransferBuffer(m_device, uploadBuffer);
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in SubmitDraw failed (%s)", SDL_GetError());
return;
}
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTransferBufferLocation transferLocation = {};
transferLocation.transfer_buffer = uploadBuffer;
SDL_GPUBufferRegion bufferRegion = {};
bufferRegion.buffer = m_vertexBuffer;
bufferRegion.size = static_cast<Uint32>(sizeof(D3DRMVERTEX) * m_vertexCount);
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
auto& mesh = m_meshs[meshId];
// Render the graphics
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.load_op = SDL_GPU_LOADOP_LOAD;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_LOAD;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_BindGPUGraphicsPipeline(renderPass, appearance.color.a == 255 ? m_opaquePipeline : m_transparentPipeline);
m_fragmentShadingData.useTexture = appearance.textureId != NO_TEXTURE_ID;
SDL_GPUTextureSamplerBinding samplerBinding = {};
samplerBinding.texture =
m_fragmentShadingData.useTexture ? m_textures[appearance.textureId].gpuTexture : m_dummyTexture;
samplerBinding.sampler = m_sampler;
SDL_BindGPUFragmentSamplers(renderPass, 0, &samplerBinding, 1);
SDL_PushGPUVertexUniformData(cmdbuf, 0, &m_uniforms, sizeof(m_uniforms));
SDL_PushGPUFragmentUniformData(cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData));
if (m_vertexCount) {
SDL_GPUBufferBinding vertexBufferBinding = {};
vertexBufferBinding.buffer = m_vertexBuffer;
vertexBufferBinding.offset = 0;
SDL_BindGPUVertexBuffers(renderPass, 0, &vertexBufferBinding, 1);
SDL_DrawGPUPrimitives(renderPass, m_vertexCount, 1, 0, 0);
}
SDL_EndGPURenderPass(renderPass);
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
if (!fence || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) {
if (fence) {
SDL_ReleaseGPUFence(m_device, fence);
}
return;
}
SDL_ReleaseGPUFence(m_device, fence);
SDL_GPUTexture* texture = useTexture ? m_textures[appearance.textureId].gpuTexture : m_dummyTexture;
SDL_GPUTextureSamplerBinding samplerBinding = {texture, m_sampler};
SDL_BindGPUFragmentSamplers(m_renderPass, 0, &samplerBinding, 1);
SDL_PushGPUVertexUniformData(m_cmdbuf, 0, &m_uniforms, sizeof(m_uniforms));
SDL_PushGPUFragmentUniformData(m_cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData));
SDL_GPUBufferBinding vertexBufferBinding = {mesh.vertexBuffer};
SDL_BindGPUVertexBuffers(m_renderPass, 0, &vertexBufferBinding, 1);
SDL_DrawGPUPrimitives(m_renderPass, mesh.vertexCount, 1, 0, 0);
}
HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
{
SDL_EndGPURenderPass(m_renderPass);
m_renderPass = nullptr;
// Download rendered image
SDL_GPUTextureRegion region = {};
region.texture = m_transferTexture;
@ -742,23 +761,23 @@ HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
SDL_GPUTextureTransferInfo transferInfo = {};
transferInfo.transfer_buffer = m_downloadBuffer;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in FinalizeFrame failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(m_cmdbuf);
SDL_DownloadFromGPUTexture(copyPass, &region, &transferInfo);
SDL_EndGPUCopyPass(copyPass);
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
if (!fence || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) {
if (fence) {
SDL_ReleaseGPUFence(m_device, fence);
}
WaitForPendingUpload();
// Render the frame
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf);
m_cmdbuf = nullptr;
if (!fence) {
return DDERR_GENERIC;
}
bool success = SDL_WaitForGPUFences(m_device, true, &fence, 1);
SDL_ReleaseGPUFence(m_device, fence);
if (!success) {
return DDERR_GENERIC;
}
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false);
if (!downloadedData) {
return DDERR_GENERIC;

View File

@ -185,7 +185,7 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(
if (appearance.shininess != 0.0f) {
// Using dotNL ignores view angle, but this matches DirectX 5 behavior.
float spec = std::pow(dotNL, appearance.shininess);
float spec = std::pow(dotNL, appearance.shininess * m_shininessFactor);
specular.r += spec * lightColor.r;
specular.g += spec * lightColor.g;
specular.b += spec * lightColor.b;
@ -439,6 +439,78 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture)
return static_cast<Uint32>(m_textures.size() - 1);
}
MeshCache UploadMesh(const MeshGroup& meshGroup)
{
MeshCache cache{&meshGroup, meshGroup.version};
cache.flat = meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT;
std::vector<D3DRMVERTEX> vertices;
if (cache.flat) {
FlattenSurfaces(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
meshGroup.texture != nullptr,
cache.vertices,
cache.indices
);
}
else {
cache.vertices.assign(meshGroup.vertices.begin(), meshGroup.vertices.end());
cache.indices.assign(meshGroup.indices.begin(), meshGroup.indices.end());
}
return cache;
}
struct MeshDestroyContext {
Direct3DRMSoftwareRenderer* renderer;
Uint32 id;
};
void Direct3DRMSoftwareRenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh)
{
auto* ctx = new MeshDestroyContext{this, id};
mesh->AddDestroyCallback(
[](IDirect3DRMObject*, void* arg) {
auto* ctx = static_cast<MeshDestroyContext*>(arg);
ctx->renderer->m_meshs[ctx->id].meshGroup = nullptr;
delete ctx;
},
ctx
);
}
Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup)
{
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (cache.meshGroup == meshGroup) {
if (cache.version != meshGroup->version) {
cache = std::move(UploadMesh(*meshGroup));
}
return i;
}
}
auto newCache = UploadMesh(*meshGroup);
for (Uint32 i = 0; i < m_meshs.size(); ++i) {
auto& cache = m_meshs[i];
if (!cache.meshGroup) {
cache = std::move(newCache);
AddMeshDestroyCallback(i, mesh);
return i;
}
}
m_meshs.push_back(std::move(newCache));
AddMeshDestroyCallback((Uint32) (m_meshs.size() - 1), mesh);
return (Uint32) (m_meshs.size() - 1);
}
DWORD Direct3DRMSoftwareRenderer::GetWidth()
{
return m_width;
@ -483,10 +555,7 @@ HRESULT Direct3DRMSoftwareRenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
}
void Direct3DRMSoftwareRenderer::SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -495,29 +564,12 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
D3DRMMATRIX4D mvMatrix;
MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix);
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
if (appearance.flat) {
// FIXME move this to a one time mesh upload stage
FlattenSurfaces(
vertices,
vertexCount,
indices,
indexCount,
appearance.textureId != NO_TEXTURE_ID,
newVertices,
newIndices
);
}
else {
newVertices.assign(vertices, vertices + vertexCount);
newIndices.assign(indices, indices + indexCount);
}
auto& mesh = m_meshs[meshId];
// Pre-transform all vertex positions and normals
std::vector<D3DRMVERTEX> transformedVerts(newVertices.size());
for (size_t i = 0; i < newVertices.size(); ++i) {
const D3DRMVERTEX& src = newVertices[i];
std::vector<D3DRMVERTEX> transformedVerts(mesh.vertices.size());
for (size_t i = 0; i < mesh.vertices.size(); ++i) {
const D3DRMVERTEX& src = mesh.vertices[i];
D3DRMVERTEX& dst = transformedVerts[i];
dst.position = TransformPoint(src.position, mvMatrix);
// TODO defer normal transformation til lighting to allow culling first
@ -526,9 +578,11 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
}
// Assemble triangles using index buffer
for (size_t i = 0; i + 2 < newIndices.size(); i += 3) {
for (size_t i = 0; i + 2 < mesh.indices.size(); i += 3) {
DrawTriangleClipped(
{transformedVerts[newIndices[i]], transformedVerts[newIndices[i + 1]], transformedVerts[newIndices[i + 2]]},
{transformedVerts[mesh.indices[i]],
transformedVerts[mesh.indices[i + 1]],
transformedVerts[mesh.indices[i + 2]]},
appearance
);
}

View File

@ -117,7 +117,12 @@ HRESULT Direct3DRMMeshImpl::SetGroupColor(DWORD groupIndex, D3DCOLOR color)
return DDERR_INVALIDPARAMS;
}
m_groups[groupIndex].color = color;
m_groups[groupIndex].color = {
static_cast<Uint8>((color >> 16) & 0xFF),
static_cast<Uint8>((color >> 8) & 0xFF),
static_cast<Uint8>((color >> 0) & 0xFF),
static_cast<Uint8>((color >> 24) & 0xFF)
};
return DD_OK;
}
@ -127,10 +132,9 @@ HRESULT Direct3DRMMeshImpl::SetGroupColorRGB(DWORD groupIndex, float r, float g,
return DDERR_INVALIDPARAMS;
}
D3DCOLOR color = (0xFF << 24) | (static_cast<BYTE>(r * 255.0f) << 16) | (static_cast<BYTE>(g * 255.0f) << 8) |
(static_cast<BYTE>(b * 255.0f));
m_groups[groupIndex]
.color = {static_cast<Uint8>(r * 255.0f), static_cast<Uint8>(g * 255.0f), static_cast<Uint8>(b * 255.0f), 255};
m_groups[groupIndex].color = color;
return DD_OK;
}
@ -139,7 +143,9 @@ D3DCOLOR Direct3DRMMeshImpl::GetGroupColor(D3DRMGROUPINDEX index)
if (index < 0 || index >= static_cast<int>(m_groups.size())) {
return 0xFFFFFFFF;
}
return m_groups[index].color;
const SDL_Color& color = m_groups[index].color;
return (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
}
HRESULT Direct3DRMMeshImpl::SetGroupMaterial(DWORD groupIndex, IDirect3DRMMaterial* material)
@ -171,6 +177,7 @@ HRESULT Direct3DRMMeshImpl::SetGroupTexture(DWORD groupIndex, IDirect3DRMTexture
texture->AddRef();
group.texture = texture;
group.version++;
return DD_OK;
}
@ -229,7 +236,10 @@ HRESULT Direct3DRMMeshImpl::SetGroupQuality(DWORD groupIndex, D3DRMRENDERQUALITY
break;
}
m_groups[groupIndex].quality = quality;
auto& group = m_groups[groupIndex];
group.quality = quality;
group.version++;
return DD_OK;
}
@ -248,7 +258,8 @@ HRESULT Direct3DRMMeshImpl::SetVertices(DWORD groupIndex, int offset, int count,
return DDERR_INVALIDPARAMS;
}
auto& vertList = m_groups[groupIndex].vertices;
auto& group = m_groups[groupIndex];
auto& vertList = group.vertices;
if (offset + count > static_cast<int>(vertList.size())) {
vertList.resize(offset + count);
@ -258,6 +269,8 @@ HRESULT Direct3DRMMeshImpl::SetVertices(DWORD groupIndex, int offset, int count,
UpdateBox();
group.version++;
return DD_OK;
}

View File

@ -180,13 +180,31 @@ void ExtractFrustumPlanes(const D3DRMMATRIX4D& m)
}
}
bool IsBoxInFrustum(const D3DVECTOR corners[8], const Plane planes[6])
bool IsMeshInFrustum(Direct3DRMMeshImpl* mesh, const D3DRMMATRIX4D& worldMatrix)
{
D3DRMBOX box;
mesh->GetBox(&box);
D3DVECTOR boxCorners[8] = {
{box.min.x, box.min.y, box.min.z},
{box.min.x, box.min.y, box.max.z},
{box.min.x, box.max.y, box.min.z},
{box.min.x, box.max.y, box.max.z},
{box.max.x, box.min.y, box.min.z},
{box.max.x, box.min.y, box.max.z},
{box.max.x, box.max.y, box.min.z},
{box.max.x, box.max.y, box.max.z},
};
for (D3DVECTOR& corner : boxCorners) {
corner = TransformPoint(corner, worldMatrix);
}
for (int i = 0; i < 6; ++i) {
int out = 0;
for (int j = 0; j < 8; ++j) {
float dist = planes[i].normal.x * corners[j].x + planes[i].normal.y * corners[j].y +
planes[i].normal.z * corners[j].z + planes[i].d;
float dist = frustumPlanes[i].normal.x * boxCorners[j].x + frustumPlanes[i].normal.y * boxCorners[j].y +
frustumPlanes[i].normal.z * boxCorners[j].z + frustumPlanes[i].d;
if (dist < 0.0f) {
++out;
}
@ -210,8 +228,6 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3D
Matrix3x3 worldMatrixInvert;
D3DRMMatrixInvertForNormal(worldMatrixInvert, worldMatrix);
const float shininessFactor = m_renderer->GetShininessFactor();
IDirect3DRMVisualArray* visuals = nullptr;
frame->GetVisuals(&visuals);
DWORD n = visuals->GetSize();
@ -230,63 +246,24 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3D
Direct3DRMMeshImpl* mesh = nullptr;
visual->QueryInterface(IID_IDirect3DRMMesh, (void**) &mesh);
if (!mesh) {
visual->Release();
continue;
}
D3DRMBOX box;
mesh->GetBox(&box);
D3DVECTOR boxCorners[8] = {
{box.min.x, box.min.y, box.min.z},
{box.min.x, box.min.y, box.max.z},
{box.min.x, box.max.y, box.min.z},
{box.min.x, box.max.y, box.max.z},
{box.max.x, box.min.y, box.min.z},
{box.max.x, box.min.y, box.max.z},
{box.max.x, box.max.y, box.min.z},
{box.max.x, box.max.y, box.max.z},
};
for (D3DVECTOR& boxCorner : boxCorners) {
boxCorner = TransformPoint(boxCorner, worldMatrix);
}
if (!IsBoxInFrustum(boxCorners, frustumPlanes)) {
if (mesh) {
if (IsMeshInFrustum(mesh, worldMatrix)) {
DWORD groupCount = mesh->GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) {
const MeshGroup& meshGroup = mesh->GetGroup(gi);
m_renderer->SubmitDraw(
m_renderer->GetMeshId(mesh, &meshGroup),
worldMatrix,
worldMatrixInvert,
{meshGroup.color,
meshGroup.material ? meshGroup.material->GetPower() : 0.0f,
meshGroup.texture ? m_renderer->GetTextureId(meshGroup.texture) : NO_TEXTURE_ID,
meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT}
);
}
}
mesh->Release();
visual->Release();
continue;
}
DWORD groupCount = mesh->GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) {
const MeshGroup& meshGroup = mesh->GetGroup(gi);
Uint32 textureId = NO_TEXTURE_ID;
if (meshGroup.texture) {
textureId = m_renderer->GetTextureId(meshGroup.texture);
}
float shininess = 0.0f;
if (meshGroup.material) {
shininess = meshGroup.material->GetPower() * shininessFactor;
}
m_renderer->SubmitDraw(
meshGroup.vertices.data(),
meshGroup.vertices.size(),
meshGroup.indices.data(),
meshGroup.indices.size(),
worldMatrix,
worldMatrixInvert,
{{static_cast<Uint8>((meshGroup.color >> 16) & 0xFF),
static_cast<Uint8>((meshGroup.color >> 8) & 0xFF),
static_cast<Uint8>((meshGroup.color >> 0) & 0xFF),
static_cast<Uint8>((meshGroup.color >> 24) & 0xFF)},
shininess,
textureId,
meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT}
);
}
mesh->Release();
visual->Release();
}
visuals->Release();

View File

@ -6,11 +6,12 @@
#include <vector>
struct MeshGroup {
D3DCOLOR color = 0xFFFFFFFF;
SDL_Color color = {0xFF, 0xFF, 0xFF, 0xFF};
IDirect3DRMTexture* texture = nullptr;
IDirect3DRMMaterial* material = nullptr;
D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD;
int vertexPerFace = 0;
int version = 0;
std::vector<D3DRMVERTEX> vertices;
std::vector<unsigned int> indices;

View File

@ -1,5 +1,6 @@
#pragma once
#include "d3drmmesh_impl.h"
#include "mathutils.h"
#include "miniwin/d3drm.h"
#include "miniwin/miniwindevice.h"
@ -35,16 +36,14 @@ public:
virtual void PushLights(const SceneLight* vertices, size_t count) = 0;
virtual void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) = 0;
virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0;
virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0;
virtual DWORD GetWidth() = 0;
virtual DWORD GetHeight() = 0;
virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0;
virtual const char* GetName() = 0;
virtual HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) = 0;
virtual void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance

View File

@ -16,6 +16,16 @@ struct GLTextureCacheEntry {
GLuint glTextureId;
};
struct GLMeshCacheEntry {
const MeshGroup* meshGroup;
int version;
bool flat;
std::vector<D3DVECTOR> positions;
std::vector<D3DVECTOR> normals;
std::vector<TexCoord> texcoords;
std::vector<DWORD> indices;
};
class OpenGL15Renderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
@ -24,16 +34,14 @@ public:
void PushLights(const SceneLight* lightsArray, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -42,7 +50,9 @@ public:
private:
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
std::vector<GLTextureCacheEntry> m_textures;
std::vector<GLMeshCacheEntry> m_meshs;
D3DRMMATRIX4D m_viewMatrix;
D3DRMMATRIX4D m_projection;
SDL_Surface* m_renderedImage;

View File

@ -34,12 +34,20 @@ struct SDL3TextureCache {
SDL_GPUTexture* gpuTexture;
};
struct SDL3MeshCache {
const MeshGroup* meshGroup;
int version;
SDL_GPUBuffer* vertexBuffer;
size_t vertexCount;
};
class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
~Direct3DRMSDL3GPURenderer() override;
void PushLights(const SceneLight* vertices, size_t count) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
@ -47,10 +55,7 @@ public:
const char* GetName() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -66,25 +71,27 @@ private:
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUTexture* dummyTexture,
SDL_GPUSampler* sampler,
SDL_GPUTransferBuffer* uploadBuffer,
SDL_GPUTransferBuffer* downloadBuffer
);
void WaitForPendingUpload();
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
SDL_GPUTransferBuffer* GetUploadBuffer(size_t size);
SDL_GPUTexture* CreateTextureFromSurface(SDL_Surface* surface);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
SDL3MeshCache UploadMesh(const MeshGroup& meshGroup);
DWORD m_width;
DWORD m_height;
D3DVALUE m_front;
D3DVALUE m_back;
int m_vertexCount;
int m_vertexBufferCount = 0;
ViewportUniforms m_uniforms;
FragmentShadingData m_fragmentShadingData;
D3DDEVICEDESC m_desc;
D3DRMMATRIX4D m_viewMatrix;
std::vector<SDL3TextureCache> m_textures;
std::vector<SDL3MeshCache> m_meshs;
SDL_GPUDevice* m_device;
SDL_GPUGraphicsPipeline* m_opaquePipeline;
SDL_GPUGraphicsPipeline* m_transparentPipeline;
@ -96,6 +103,9 @@ private:
SDL_GPUTransferBuffer* m_downloadBuffer;
SDL_GPUBuffer* m_vertexBuffer = nullptr;
SDL_GPUSampler* m_sampler;
SDL_GPUCommandBuffer* m_cmdbuf = nullptr;
SDL_GPURenderPass* m_renderPass = nullptr;
SDL_GPUFence* m_uploadFence = nullptr;
};
inline static void Direct3DRMSDL3GPU_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)

View File

@ -16,11 +16,20 @@ struct TextureCache {
SDL_Surface* cached;
};
struct MeshCache {
const MeshGroup* meshGroup;
int version;
bool flat;
std::vector<D3DRMVERTEX> vertices;
std::vector<DWORD> indices;
};
class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
public:
Direct3DRMSoftwareRenderer(DWORD width, DWORD height);
void PushLights(const SceneLight* vertices, size_t count) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
@ -28,10 +37,7 @@ public:
const char* GetName() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
DWORD meshId,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -51,6 +57,7 @@ private:
void BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
SDL_Color ApplyLighting(const D3DVECTOR& position, const D3DVECTOR& normal, const Appearance& appearance);
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
DWORD m_width;
DWORD m_height;
@ -59,6 +66,7 @@ private:
int m_bytesPerPixel;
std::vector<SceneLight> m_lights;
std::vector<TextureCache> m_textures;
std::vector<MeshCache> m_meshs;
D3DVALUE m_front;
D3DVALUE m_back;
D3DRMMATRIX4D m_viewMatrix;