mirror of
https://github.com/isledecomp/isle-portable.git
synced 2025-09-24 04:26:55 -04:00
Upload models to GPU before rendering (#272)
This commit is contained in:
parent
9ebeda5c0e
commit
c8b8035de8
@ -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();
|
||||
}
|
||||
|
@ -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, ®ion, &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;
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user