diff --git a/miniwin/src/d3drm/backends/opengl15/renderer.cpp b/miniwin/src/d3drm/backends/opengl15/renderer.cpp index ed13ed36..476bad75 100644 --- a/miniwin/src/d3drm/backends/opengl15/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl15/renderer.cpp @@ -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 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(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 newVertices; - std::vector 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 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 positions; - positions.resize(newVertices.size()); - std::transform(newVertices.begin(), newVertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { - return v.position; - }); - std::vector 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(newIndices.size()), GL_UNSIGNED_INT, newIndices.data()); + glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_INT, mesh.indices.data()); glPopMatrix(); } diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index d61f6954..c9dba602 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -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(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 flatVertices; + if (meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT) { + std::vector newVertices; + std::vector 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(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(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 flatVertices; - if (appearance.flat) { - std::vector newVertices; - std::vector 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(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(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; diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index 0fc243c1..f7b76ea3 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -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(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 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(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 newVertices; - std::vector 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 transformedVerts(newVertices.size()); - for (size_t i = 0; i < newVertices.size(); ++i) { - const D3DRMVERTEX& src = newVertices[i]; + std::vector 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 ); } diff --git a/miniwin/src/d3drm/d3drmmesh.cpp b/miniwin/src/d3drm/d3drmmesh.cpp index 325d0a75..653f993d 100644 --- a/miniwin/src/d3drm/d3drmmesh.cpp +++ b/miniwin/src/d3drm/d3drmmesh.cpp @@ -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((color >> 16) & 0xFF), + static_cast((color >> 8) & 0xFF), + static_cast((color >> 0) & 0xFF), + static_cast((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(r * 255.0f) << 16) | (static_cast(g * 255.0f) << 8) | - (static_cast(b * 255.0f)); + m_groups[groupIndex] + .color = {static_cast(r * 255.0f), static_cast(g * 255.0f), static_cast(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(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(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; } diff --git a/miniwin/src/d3drm/d3drmviewport.cpp b/miniwin/src/d3drm/d3drmviewport.cpp index 3a8f694a..d9546d74 100644 --- a/miniwin/src/d3drm/d3drmviewport.cpp +++ b/miniwin/src/d3drm/d3drmviewport.cpp @@ -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((meshGroup.color >> 16) & 0xFF), - static_cast((meshGroup.color >> 8) & 0xFF), - static_cast((meshGroup.color >> 0) & 0xFF), - static_cast((meshGroup.color >> 24) & 0xFF)}, - shininess, - textureId, - meshGroup.quality == D3DRMRENDER_FLAT || meshGroup.quality == D3DRMRENDER_UNLITFLAT} - ); - } - mesh->Release(); visual->Release(); } visuals->Release(); diff --git a/miniwin/src/internal/d3drmmesh_impl.h b/miniwin/src/internal/d3drmmesh_impl.h index 7e6dda68..3803b59e 100644 --- a/miniwin/src/internal/d3drmmesh_impl.h +++ b/miniwin/src/internal/d3drmmesh_impl.h @@ -6,11 +6,12 @@ #include 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 vertices; std::vector indices; diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index 4703a31e..924860f5 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -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 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { 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 diff --git a/miniwin/src/internal/d3drmrenderer_opengl15.h b/miniwin/src/internal/d3drmrenderer_opengl15.h index 16ed55c7..8d88f4c0 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl15.h +++ b/miniwin/src/internal/d3drmrenderer_opengl15.h @@ -16,6 +16,16 @@ struct GLTextureCacheEntry { GLuint glTextureId; }; +struct GLMeshCacheEntry { + const MeshGroup* meshGroup; + int version; + bool flat; + std::vector positions; + std::vector normals; + std::vector texcoords; + std::vector indices; +}; + class OpenGL15Renderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); @@ -24,16 +34,14 @@ class OpenGL15Renderer : public Direct3DRMRenderer { 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 @@ class OpenGL15Renderer : public Direct3DRMRenderer { private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); + void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); std::vector m_textures; + std::vector m_meshs; D3DRMMATRIX4D m_viewMatrix; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index 168bde51..ce21d149 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -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 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { 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 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { 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 m_textures; + std::vector m_meshs; SDL_GPUDevice* m_device; SDL_GPUGraphicsPipeline* m_opaquePipeline; SDL_GPUGraphicsPipeline* m_transparentPipeline; @@ -96,6 +103,9 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { 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) diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 4ceb343c..5293d2d1 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -16,11 +16,20 @@ struct TextureCache { SDL_Surface* cached; }; +struct MeshCache { + const MeshGroup* meshGroup; + int version; + bool flat; + std::vector vertices; + std::vector 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 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { 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 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { 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 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { int m_bytesPerPixel; std::vector m_lights; std::vector m_textures; + std::vector m_meshs; D3DVALUE m_front; D3DVALUE m_back; D3DRMMATRIX4D m_viewMatrix;