miniwin: Refactor D3DRM

This commit is contained in:
Anders Jenbo 2025-05-21 13:55:43 +02:00
parent 035ba477e7
commit 14c564758a
11 changed files with 784 additions and 492 deletions

View File

@ -97,6 +97,8 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL
miniwin/miniwin/src/miniwin_ddsurface.cpp miniwin/miniwin/src/miniwin_ddsurface.cpp
miniwin/miniwin/src/miniwin_ddraw.cpp miniwin/miniwin/src/miniwin_ddraw.cpp
miniwin/miniwin/src/miniwin_d3drm.cpp miniwin/miniwin/src/miniwin_d3drm.cpp
miniwin/miniwin/src/miniwin_d3drmdevice.cpp
miniwin/miniwin/src/miniwin_d3drmviewport.cpp
) )
# Force reported render mods from MiniWin # Force reported render mods from MiniWin
target_compile_definitions(miniwin PRIVATE MINIWIN_PIXELFORMAT=SDL_PIXELFORMAT_RGB565) target_compile_definitions(miniwin PRIVATE MINIWIN_PIXELFORMAT=SDL_PIXELFORMAT_RGB565)

View File

@ -1,3 +1,5 @@
#pragma once
#include <type_traits> #include <type_traits>
// Enable bitwise ops only for enum classes with the ENABLE_BITMASK_OPERATORS trait // Enable bitwise ops only for enum classes with the ENABLE_BITMASK_OPERATORS trait

View File

@ -13,7 +13,7 @@
// --- Typedefs --- // --- Typedefs ---
typedef float D3DVAL; typedef float D3DVAL;
typedef void* LPD3DRM_APPDATA; typedef void* LPD3DRM_APPDATA;
typedef unsigned int D3DRMGROUPINDEX; typedef DWORD D3DRMGROUPINDEX;
typedef DWORD D3DCOLOR, *LPD3DCOLOR; typedef DWORD D3DCOLOR, *LPD3DCOLOR;
typedef float D3DVALUE, *LPD3DVALUE; typedef float D3DVALUE, *LPD3DVALUE;
@ -116,16 +116,16 @@ typedef struct D3DRMPALETTEENTRY {
} D3DRMPALETTEENTRY; } D3DRMPALETTEENTRY;
typedef struct D3DRMIMAGE { typedef struct D3DRMIMAGE {
unsigned int width, height, depth, bytes_per_line; DWORD width, height, depth, bytes_per_line;
unsigned int red_mask, green_mask, blue_mask, alpha_mask; DWORD red_mask, green_mask, blue_mask, alpha_mask;
unsigned int palette_size; DWORD palette_size;
D3DRMPALETTEENTRY* palette; D3DRMPALETTEENTRY* palette;
void* buffer1; void* buffer1;
void* buffer2; void* buffer2;
void* data; void* data;
int rgb; int rgb;
int aspectx, aspecty; int aspectx, aspecty;
unsigned int format; DWORD format;
} D3DRMIMAGE; } D3DRMIMAGE;
typedef struct D3DRMMATRIX4D { typedef struct D3DRMMATRIX4D {
@ -179,11 +179,11 @@ struct IDirect3DRMMesh : public IDirect3DRMVisual {
) = 0; ) = 0;
virtual HRESULT GetGroup( virtual HRESULT GetGroup(
int groupIndex, int groupIndex,
unsigned int* vertexCount, DWORD* vertexCount,
unsigned int* faceCount, DWORD* faceCount,
unsigned int* vertexPerFace, DWORD* vertexPerFace,
DWORD* dataSize, DWORD* dataSize,
unsigned int* data DWORD* data
) = 0; ) = 0;
virtual HRESULT SetGroupColor(int groupIndex, D3DCOLOR color) = 0; virtual HRESULT SetGroupColor(int groupIndex, D3DCOLOR color) = 0;
virtual HRESULT SetGroupColorRGB(int groupIndex, float r, float g, float b) = 0; virtual HRESULT SetGroupColorRGB(int groupIndex, float r, float g, float b) = 0;
@ -284,8 +284,8 @@ struct IDirect3DRMViewport : public IDirect3DRMObject {
virtual D3DVALUE GetBack() = 0; virtual D3DVALUE GetBack() = 0;
virtual HRESULT SetField(D3DVALUE field) = 0; virtual HRESULT SetField(D3DVALUE field) = 0;
virtual D3DVALUE GetField() = 0; virtual D3DVALUE GetField() = 0;
virtual int GetWidth() = 0; virtual DWORD GetWidth() = 0;
virtual int GetHeight() = 0; virtual DWORD GetHeight() = 0;
virtual HRESULT Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world) = 0; virtual HRESULT Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world) = 0;
virtual HRESULT InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen) = 0; virtual HRESULT InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen) = 0;
virtual HRESULT Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray) = 0; virtual HRESULT Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray) = 0;
@ -305,11 +305,11 @@ struct IDirect3DRMWinDevice : virtual public IDirect3DRMObject {
}; };
struct IDirect3DRMDevice : virtual public IDirect3DRMObject { struct IDirect3DRMDevice : virtual public IDirect3DRMObject {
virtual unsigned int GetWidth() = 0; virtual DWORD GetWidth() = 0;
virtual unsigned int GetHeight() = 0; virtual DWORD GetHeight() = 0;
virtual HRESULT SetBufferCount(int count) = 0; virtual HRESULT SetBufferCount(int count) = 0;
virtual HRESULT GetBufferCount() = 0; virtual HRESULT GetBufferCount() = 0;
virtual HRESULT SetShades(unsigned int shadeCount) = 0; virtual HRESULT SetShades(DWORD shadeCount) = 0;
virtual HRESULT GetShades() = 0; virtual HRESULT GetShades() = 0;
virtual HRESULT SetQuality(D3DRMRENDERQUALITY quality) = 0; virtual HRESULT SetQuality(D3DRMRENDERQUALITY quality) = 0;
virtual D3DRMRENDERQUALITY GetQuality() = 0; virtual D3DRMRENDERQUALITY GetQuality() = 0;
@ -353,8 +353,8 @@ struct IDirect3DRM : virtual public IUnknown {
int height, int height,
IDirect3DRMViewport** outViewport IDirect3DRMViewport** outViewport
) = 0; ) = 0;
virtual HRESULT SetDefaultTextureShades(unsigned int count) = 0; virtual HRESULT SetDefaultTextureShades(DWORD count) = 0;
virtual HRESULT SetDefaultTextureColors(unsigned int count) = 0; virtual HRESULT SetDefaultTextureColors(DWORD count) = 0;
}; };
typedef IDirect3DRM *LPDIRECT3DRM, **LPLPDIRECT3DRM; typedef IDirect3DRM *LPDIRECT3DRM, **LPLPDIRECT3DRM;

View File

@ -0,0 +1,76 @@
#pragma once
#include "miniwin_d3drm.h"
#include <SDL3/SDL.h>
#include <algorithm>
#include <vector>
typedef struct PositionColorVertex {
float x, y, z;
Uint8 r, g, b, a;
} PositionColorVertex;
template <typename InterfaceType, typename ArrayInterface>
class Direct3DRMArrayBase : public ArrayInterface {
public:
~Direct3DRMArrayBase() override
{
for (auto* item : items) {
if (item) {
item->Release();
}
}
}
DWORD GetSize() override { return static_cast<DWORD>(items.size()); }
HRESULT AddElement(InterfaceType* in) override
{
if (!in) {
return DDERR_INVALIDPARAMS;
}
in->AddRef();
items.push_back(in);
return DD_OK;
}
HRESULT GetElement(DWORD index, InterfaceType** out) override
{
if (index >= items.size()) {
return DDERR_INVALIDPARAMS;
}
*out = static_cast<InterfaceType*>(items[index]);
if (*out) {
(*out)->AddRef();
}
return DD_OK;
}
HRESULT DeleteElement(InterfaceType* element) override
{
auto it = std::find(items.begin(), items.end(), element);
if (it == items.end()) {
return DDERR_INVALIDPARAMS;
}
(*it)->Release();
items.erase(it);
return DD_OK;
}
protected:
std::vector<InterfaceType*> items;
};
struct Direct3DRMFrameArrayImpl : public Direct3DRMArrayBase<IDirect3DRMFrame, IDirect3DRMFrameArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct Direct3DRMLightArrayImpl : public Direct3DRMArrayBase<IDirect3DRMLight, IDirect3DRMLightArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct Direct3DRMViewportArrayImpl : public Direct3DRMArrayBase<IDirect3DRMViewport, IDirect3DRMViewportArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct Direct3DRMVisualArrayImpl : public Direct3DRMArrayBase<IDirect3DRMVisual, IDirect3DRMVisualArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};

View File

@ -0,0 +1,38 @@
#pragma once
#include "miniwin_d3drm.h"
#include "miniwin_d3drmobject_p.h"
#include <SDL3/SDL.h>
struct Direct3DRMDevice2Impl : public Direct3DRMObjectBase<IDirect3DRMDevice2> {
Direct3DRMDevice2Impl(DWORD width, DWORD height, SDL_GPUDevice* device);
~Direct3DRMDevice2Impl() override;
DWORD GetWidth() override;
DWORD GetHeight() override;
HRESULT SetBufferCount(int count) override;
HRESULT GetBufferCount() override;
HRESULT SetShades(DWORD shadeCount) override;
HRESULT GetShades() override;
HRESULT SetQuality(D3DRMRENDERQUALITY quality) override;
D3DRMRENDERQUALITY GetQuality() override;
HRESULT SetDither(int dither) override;
HRESULT GetDither() override;
HRESULT SetTextureQuality(D3DRMTEXTUREQUALITY quality) override;
D3DRMTEXTUREQUALITY GetTextureQuality() override;
HRESULT SetRenderMode(D3DRMRENDERMODE mode) override;
D3DRMRENDERMODE GetRenderMode() override;
/**
* @brief Recalculating light positions, animation updates, etc.
*/
HRESULT Update() override;
HRESULT AddViewport(IDirect3DRMViewport* viewport) override;
HRESULT GetViewports(IDirect3DRMViewportArray** ppViewportArray) override;
SDL_GPUDevice* m_device;
private:
DWORD m_width;
DWORD m_height;
IDirect3DRMViewportArray* m_viewports;
};

View File

@ -0,0 +1,70 @@
#pragma once
#include "miniwin_d3drm.h"
#include <SDL3/SDL.h>
#include <vector>
template <typename T>
struct Direct3DRMObjectBase : public T {
ULONG Release() override
{
if (IUnknown::m_refCount == 1) {
for (auto it = m_callbacks.cbegin(); it != m_callbacks.cend(); it++) {
it->first(this, it->second);
}
}
SDL_free(m_name);
return this->T::Release();
}
HRESULT AddDestroyCallback(D3DRMOBJECTCALLBACK callback, void* arg) override
{
m_callbacks.push_back(std::make_pair(callback, arg));
return D3DRM_OK;
}
HRESULT DeleteDestroyCallback(D3DRMOBJECTCALLBACK callback, void* arg) override
{
for (auto it = m_callbacks.cbegin(); it != m_callbacks.cend(); it++) {
if (it->first == callback && it->second == arg) {
m_callbacks.erase(it);
return D3DRM_OK;
}
}
return D3DRMERR_NOTFOUND;
}
HRESULT SetAppData(LPD3DRM_APPDATA appData) override
{
m_appData = appData;
return D3DRM_OK;
}
LPVOID GetAppData() override { return m_appData; }
HRESULT SetName(const char* name) override
{
SDL_free(m_name);
m_name = NULL;
if (name) {
m_name = SDL_strdup(name);
}
return D3DRM_OK;
}
HRESULT GetName(DWORD* size, char* name) override
{
if (!size) {
return DDERR_INVALIDPARAMS;
}
const char* s = m_name ? m_name : "";
size_t l = SDL_strlen(s);
if (name) {
SDL_strlcpy(name, s, *size);
}
else {
*size = l + 1;
}
return D3DRM_OK;
}
private:
std::vector<std::pair<D3DRMOBJECTCALLBACK, void*>> m_callbacks;
LPD3DRM_APPDATA m_appData = nullptr;
char* m_name = nullptr;
};

View File

@ -0,0 +1,56 @@
#pragma once
#include "miniwin_d3drm.h"
#include "miniwin_d3drmdevice_p.h"
#include "miniwin_d3drmobject_p.h"
#include <SDL3/SDL.h>
struct Direct3DRMViewportImpl : public Direct3DRMObjectBase<IDirect3DRMViewport> {
Direct3DRMViewportImpl(
DWORD width,
DWORD height,
SDL_GPUDevice* device,
SDL_GPUTexture* transferTexture,
SDL_GPUTransferBuffer* downloadTransferBuffer,
SDL_GPUGraphicsPipeline* pipeline
);
~Direct3DRMViewportImpl() override;
HRESULT Render(IDirect3DRMFrame* group) override;
/**
* @brief Blit the render back to our backbuffer
*/
HRESULT ForceUpdate(int x, int y, int w, int h) override;
HRESULT Clear() override;
HRESULT SetCamera(IDirect3DRMFrame* camera) override;
HRESULT GetCamera(IDirect3DRMFrame** camera) override;
HRESULT SetProjection(D3DRMPROJECTIONTYPE type) override;
D3DRMPROJECTIONTYPE GetProjection() override;
HRESULT SetFront(D3DVALUE z) override;
D3DVALUE GetFront() override;
HRESULT SetBack(D3DVALUE z) override;
D3DVALUE GetBack() override;
HRESULT SetField(D3DVALUE field) override;
D3DVALUE GetField() override;
DWORD GetWidth() override;
DWORD GetHeight() override;
HRESULT Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world) override;
HRESULT InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen) override;
HRESULT Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray) override;
void CloseDevice();
void Update();
private:
void FreeDeviceResources();
int m_vertexCount;
bool m_updated = false;
DWORD m_width;
DWORD m_height;
IDirect3DRMFrame* m_camera = nullptr;
SDL_GPUDevice* m_device;
SDL_GPUGraphicsPipeline* m_pipeline;
SDL_GPUTexture* m_transferTexture;
SDL_GPUTransferBuffer* m_downloadTransferBuffer;
SDL_GPUBuffer* m_vertexBuffer;
SDL_Surface* m_renderedImage = nullptr;
};

View File

@ -1,81 +1,12 @@
#include "miniwin_d3drm.h" #include "miniwin_d3drm.h"
#include "miniwin_ddsurface_p.h"
#include "ShaderIndex.h" #include "ShaderIndex.h"
#include "miniwin_d3drm_p.h"
#include "miniwin_d3drmobject_p.h"
#include "miniwin_d3drmviewport_p.h"
#include "miniwin_ddsurface_p.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <algorithm>
#include <assert.h>
#include <vector>
typedef struct PositionColorVertex {
float x, y, z;
Uint8 r, g, b, a;
} PositionColorVertex;
template <typename InterfaceType, typename ArrayInterface>
class Direct3DRMArrayBase : public ArrayInterface {
public:
~Direct3DRMArrayBase() override
{
for (auto* item : items) {
if (item) {
item->Release();
}
}
}
DWORD GetSize() override { return static_cast<DWORD>(items.size()); }
HRESULT AddElement(InterfaceType* in) override
{
if (!in) {
return DDERR_INVALIDPARAMS;
}
in->AddRef();
items.push_back(in);
return DD_OK;
}
HRESULT GetElement(DWORD index, InterfaceType** out) override
{
if (index >= items.size()) {
return DDERR_INVALIDPARAMS;
}
*out = static_cast<InterfaceType*>(items[index]);
if (*out) {
(*out)->AddRef();
}
return DD_OK;
}
HRESULT DeleteElement(InterfaceType* element) override
{
auto it = std::find(items.begin(), items.end(), element);
if (it == items.end()) {
return DDERR_INVALIDPARAMS;
}
(*it)->Release();
items.erase(it);
return DD_OK;
}
protected:
std::vector<InterfaceType*> items;
};
struct Direct3DRMFrameArrayImpl : public Direct3DRMArrayBase<IDirect3DRMFrame, IDirect3DRMFrameArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct Direct3DRMLightArrayImpl : public Direct3DRMArrayBase<IDirect3DRMLight, IDirect3DRMLightArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct Direct3DRMViewportArrayImpl : public Direct3DRMArrayBase<IDirect3DRMViewport, IDirect3DRMViewportArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct Direct3DRMVisualArrayImpl : public Direct3DRMArrayBase<IDirect3DRMVisual, IDirect3DRMVisualArray> {
using Direct3DRMArrayBase::Direct3DRMArrayBase;
};
struct PickRecord { struct PickRecord {
IDirect3DRMVisual* visual; IDirect3DRMVisual* visual;
@ -130,69 +61,6 @@ struct Direct3DRMWinDeviceImpl : public IDirect3DRMWinDevice {
void HandlePaint(void* p_dc) override {} void HandlePaint(void* p_dc) override {}
}; };
template <typename T>
struct Direct3DRMObjectBase : public T {
ULONG Release() override
{
if (IUnknown::m_refCount == 1) {
for (auto it = m_callbacks.cbegin(); it != m_callbacks.cend(); it++) {
it->first(this, it->second);
}
}
return this->T::Release();
}
HRESULT AddDestroyCallback(D3DRMOBJECTCALLBACK callback, void* arg) override
{
m_callbacks.push_back(std::make_pair(callback, arg));
return D3DRM_OK;
}
HRESULT DeleteDestroyCallback(D3DRMOBJECTCALLBACK callback, void* arg) override
{
for (auto it = m_callbacks.cbegin(); it != m_callbacks.cend(); it++) {
if (it->first == callback && it->second == arg) {
m_callbacks.erase(it);
return D3DRM_OK;
}
}
return D3DRMERR_NOTFOUND;
}
HRESULT SetAppData(LPD3DRM_APPDATA appData) override
{
m_appData = appData;
return D3DRM_OK;
}
LPVOID GetAppData() override { return m_appData; }
HRESULT SetName(const char* name) override
{
SDL_free(m_name);
m_name = NULL;
if (name) {
m_name = SDL_strdup(name);
}
return D3DRM_OK;
}
HRESULT GetName(DWORD* size, char* name) override
{
if (!size) {
return DDERR_INVALIDPARAMS;
}
const char* s = m_name ? m_name : "";
size_t l = SDL_strlen(s);
if (name) {
SDL_strlcpy(name, s, *size);
}
else {
*size = l + 1;
}
return D3DRM_OK;
}
private:
std::vector<std::pair<D3DRMOBJECTCALLBACK, void*>> m_callbacks;
LPD3DRM_APPDATA m_appData = nullptr;
char* m_name = nullptr;
};
struct Direct3DRMMeshImpl : public Direct3DRMObjectBase<IDirect3DRMMesh> { struct Direct3DRMMeshImpl : public Direct3DRMObjectBase<IDirect3DRMMesh> {
HRESULT Clone(int flags, GUID iid, void** object) override HRESULT Clone(int flags, GUID iid, void** object) override
{ {
@ -211,11 +79,11 @@ struct Direct3DRMMeshImpl : public Direct3DRMObjectBase<IDirect3DRMMesh> {
} }
HRESULT GetGroup( HRESULT GetGroup(
int groupIndex, int groupIndex,
unsigned int* vertexCount, DWORD* vertexCount,
unsigned int* faceCount, DWORD* faceCount,
unsigned int* vertexPerFace, DWORD* vertexPerFace,
DWORD* dataSize, DWORD* dataSize,
unsigned int* data DWORD* data
) override ) override
{ {
return DD_OK; return DD_OK;
@ -263,214 +131,6 @@ struct Direct3DRMTextureImpl : public Direct3DRMObjectBase<IDirect3DRMTexture2>
HRESULT Changed(BOOL pixels, BOOL palette) override { return DD_OK; } HRESULT Changed(BOOL pixels, BOOL palette) override { return DD_OK; }
}; };
SDL_GPUShader* CompileVertexShader(SDL_GPUDevice* device, VertexShaderId id)
{
size_t size;
const SDL_GPUShaderCreateInfo* createInfo = GetVertexShaderCode(id, SDL_GetGPUShaderFormats(device));
if (!createInfo) {
return NULL;
}
SDL_GPUShader* shader = SDL_CreateGPUShader(device, createInfo);
if (!shader) {
SDL_Log("Failed to create Vertex GPU shader: %s", SDL_GetError());
}
return shader;
}
SDL_GPUShader* CompileFragmentShader(SDL_GPUDevice* device, FragmentShaderId id)
{
size_t size;
const SDL_GPUShaderCreateInfo* createInfo = GetFragmentShaderCode(id, SDL_GetGPUShaderFormats(device));
if (!createInfo) {
return NULL;
}
SDL_GPUShader* shader = SDL_CreateGPUShader(device, createInfo);
if (!shader) {
SDL_Log("Failed to create Fragment GPU shader: %s", SDL_GetError());
}
return shader;
}
SDL_GPUDevice* m_device;
SDL_GPUGraphicsPipeline* m_pipeline;
SDL_GPUTexture* m_transferTexture;
SDL_GPUTransferBuffer* m_downloadTransferBuffer;
SDL_GPUBuffer* VertexBuffer;
int m_vertexCount = 3;
struct Direct3DRMDevice2Impl : public Direct3DRMObjectBase<IDirect3DRMDevice2> {
Direct3DRMDevice2Impl()
{
m_device = SDL_CreateGPUDevice(
SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL,
true,
NULL
);
if (m_device == NULL) {
SDL_Log("GPUCreateDevice failed");
return;
}
if (DDWindow == NULL) {
SDL_Log("CreateWindow failed: %s", SDL_GetError());
return;
}
if (!SDL_ClaimWindowForGPUDevice(m_device, DDWindow)) {
SDL_Log("GPUClaimWindow failed");
return;
}
SDL_GPUShader* vertexShader = CompileVertexShader(m_device, VertexShaderId::PositionColor);
if (vertexShader == NULL) {
SDL_Log("Failed to create vertex shader!");
return;
}
SDL_GPUShader* fragmentShader = CompileFragmentShader(m_device, FragmentShaderId::SolidColor);
if (fragmentShader == NULL) {
SDL_Log("Failed to create fragment shader!");
return;
}
SDL_GPUColorTargetDescription colorTargets = {SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB};
SDL_GPUVertexBufferDescription vertexBufferDescs[] = {
{.slot = 0,
.pitch = sizeof(PositionColorVertex),
.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
.instance_step_rate = 0}
};
SDL_GPUVertexAttribute vertexAttrs[] = {
{.location = 0, .buffer_slot = 0, .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, .offset = 0},
{.location = 1,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM,
.offset = sizeof(float) * 3}
};
SDL_GPUVertexInputState vertexInputState = {
.vertex_buffer_descriptions = vertexBufferDescs,
.num_vertex_buffers = 1,
.vertex_attributes = vertexAttrs,
.num_vertex_attributes = 2
};
SDL_GPUGraphicsPipelineCreateInfo pipelineCreateInfo =
{.vertex_shader = vertexShader,
.fragment_shader = fragmentShader,
.vertex_input_state = vertexInputState,
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
.target_info = {
.color_target_descriptions = &colorTargets,
.num_color_targets = 1,
}};
m_pipeline = SDL_CreateGPUGraphicsPipeline(m_device, &pipelineCreateInfo);
if (m_pipeline == NULL) {
SDL_Log("Failed to create fill pipeline!");
return;
}
// Clean up shader resources
SDL_ReleaseGPUShader(m_device, vertexShader);
SDL_ReleaseGPUShader(m_device, fragmentShader);
// Create the vertex buffer
SDL_GPUBufferCreateInfo bufferCreateInfo = {
.usage = SDL_GPU_BUFFERUSAGE_VERTEX,
.size = (Uint32) (sizeof(PositionColorVertex) * m_vertexCount)
};
VertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
SDL_GPUTransferBufferCreateInfo transferCreateInfo = {
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
.size = (Uint32) (sizeof(PositionColorVertex) * m_vertexCount)
};
SDL_GPUTransferBuffer* transferBuffer = SDL_CreateGPUTransferBuffer(m_device, &transferCreateInfo);
PositionColorVertex* transferData =
(PositionColorVertex*) SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
transferData[0] = (PositionColorVertex){-1, -1, 0, 255, 0, 0, 255};
transferData[1] = (PositionColorVertex){1, -1, 0, 0, 0, 255, 255};
transferData[2] = (PositionColorVertex){0, 1, 0, 0, 255, 0, 128};
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* uploadCmdBuf = SDL_AcquireGPUCommandBuffer(m_device);
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(uploadCmdBuf);
SDL_GPUTransferBufferLocation transferLocation = {.transfer_buffer = transferBuffer, .offset = 0};
SDL_GPUBufferRegion bufferRegion =
{.buffer = VertexBuffer, .offset = 0, .size = (Uint32) (sizeof(PositionColorVertex) * m_vertexCount)};
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
SDL_SubmitGPUCommandBuffer(uploadCmdBuf);
SDL_ReleaseGPUTransferBuffer(m_device, transferBuffer);
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB;
textureInfo.width = 640;
textureInfo.height = 480;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
m_transferTexture = SDL_CreateGPUTexture(m_device, &textureInfo);
if (m_transferTexture == NULL) {
SDL_Log("Failed to create fill pipeline!");
return;
}
SDL_GPUTransferBufferCreateInfo downloadTransferInfo = {
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD,
.size = 640 * 480 * 4
};
m_downloadTransferBuffer = SDL_CreateGPUTransferBuffer(m_device, &downloadTransferInfo);
if (!m_downloadTransferBuffer) {
return;
}
m_viewports = new Direct3DRMViewportArrayImpl;
m_viewports->AddRef();
}
~Direct3DRMDevice2Impl() override
{
m_viewports->Release();
SDL_ReleaseGPUGraphicsPipeline(m_device, m_pipeline);
SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow);
SDL_ReleaseGPUBuffer(m_device, VertexBuffer);
SDL_DestroyWindow(DDWindow);
SDL_DestroyGPUDevice(m_device);
}
unsigned int GetWidth() override { return 640; }
unsigned int GetHeight() override { return 480; }
HRESULT SetBufferCount(int count) override { return DD_OK; }
HRESULT GetBufferCount() override { return DD_OK; }
HRESULT SetShades(unsigned int shadeCount) override { return DD_OK; }
HRESULT GetShades() override { return DD_OK; }
HRESULT SetQuality(D3DRMRENDERQUALITY quality) override { return DD_OK; }
D3DRMRENDERQUALITY GetQuality() override { return D3DRMRENDERQUALITY::GOURAUD; }
HRESULT SetDither(int dither) override { return DD_OK; }
HRESULT GetDither() override { return DD_OK; }
HRESULT SetTextureQuality(D3DRMTEXTUREQUALITY quality) override { return DD_OK; }
D3DRMTEXTUREQUALITY GetTextureQuality() override { return D3DRMTEXTUREQUALITY::LINEAR; }
HRESULT SetRenderMode(D3DRMRENDERMODE mode) override { return DD_OK; }
D3DRMRENDERMODE GetRenderMode() override { return D3DRMRENDERMODE::BLENDEDTRANSPARENCY; }
HRESULT Update() override { return DD_OK; }
HRESULT AddViewport(IDirect3DRMViewport* viewport) override { return m_viewports->AddElement(viewport); }
HRESULT GetViewports(IDirect3DRMViewportArray** ppViewportArray) override
{
*ppViewportArray = m_viewports;
return DD_OK;
}
private:
IDirect3DRMViewportArray* m_viewports;
};
struct Direct3DRMFrameImpl : public Direct3DRMObjectBase<IDirect3DRMFrame2> { struct Direct3DRMFrameImpl : public Direct3DRMObjectBase<IDirect3DRMFrame2> {
Direct3DRMFrameImpl() Direct3DRMFrameImpl()
{ {
@ -550,130 +210,76 @@ struct Direct3DRMFrameImpl : public Direct3DRMObjectBase<IDirect3DRMFrame2> {
IDirect3DRMTexture* m_texture = nullptr; IDirect3DRMTexture* m_texture = nullptr;
}; };
struct Direct3DRMViewportImpl : public Direct3DRMObjectBase<IDirect3DRMViewport> {
HRESULT Render(IDirect3DRMFrame* group) override
{
if (!m_transferTexture || !DDBackBuffer) {
return DDERR_GENERIC;
}
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (cmdbuf == NULL) {
return DDERR_GENERIC;
}
// Render the graphics
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
// Make the render target transparent so we can combine it with the back buffer
colorTargetInfo.clear_color = {0, 0, 0, 0};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, NULL);
SDL_BindGPUGraphicsPipeline(renderPass, m_pipeline);
SDL_GPUBufferBinding vertexBufferBinding = {.buffer = VertexBuffer, .offset = 0};
SDL_BindGPUVertexBuffers(renderPass, 0, &vertexBufferBinding, 1);
SDL_DrawGPUPrimitives(renderPass, m_vertexCount, 1, 0, 0);
SDL_EndGPURenderPass(renderPass);
// Download rendered image
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTextureRegion region = {};
region.texture = m_transferTexture;
region.w = DDBackBuffer->w;
region.h = DDBackBuffer->h;
region.d = 1;
SDL_GPUTextureTransferInfo transferInfo = {};
transferInfo.transfer_buffer = m_downloadTransferBuffer;
transferInfo.offset = 0;
SDL_DownloadFromGPUTexture(copyPass, &region, &transferInfo);
SDL_EndGPUCopyPass(copyPass);
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
if (!cmdbuf || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) {
return DDERR_GENERIC;
}
SDL_ReleaseGPUFence(m_device, fence);
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadTransferBuffer, false);
if (!downloadedData) {
return DDERR_GENERIC;
}
SDL_Surface* renderedImage = SDL_CreateSurfaceFrom(
DDBackBuffer->w,
DDBackBuffer->h,
SDL_PIXELFORMAT_ABGR8888,
downloadedData,
DDBackBuffer->w * 4
);
if (!renderedImage) {
return DDERR_GENERIC;
}
// Blit the render back to our backbuffer
SDL_Rect srcRect{0, 0, DDBackBuffer->w, DDBackBuffer->h};
if (renderedImage->format == DDBackBuffer->format) {
// No conversion needed
SDL_BlitSurface(renderedImage, &srcRect, DDBackBuffer, &srcRect);
SDL_DestroySurface(renderedImage);
return DD_OK;
}
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(DDBackBuffer->format);
if (details->Amask != 0) {
// Backbuffer supports transparnacy
SDL_Surface* convertedRender = SDL_ConvertSurface(renderedImage, DDBackBuffer->format);
SDL_DestroySurface(renderedImage);
SDL_BlitSurface(convertedRender, &srcRect, DDBackBuffer, &srcRect);
SDL_DestroySurface(convertedRender);
return DD_OK;
}
// Convert backbuffer to a format that supports transparancy
SDL_Surface* tempBackbuffer = SDL_ConvertSurface(DDBackBuffer, renderedImage->format);
SDL_BlitSurface(renderedImage, &srcRect, tempBackbuffer, &srcRect);
SDL_DestroySurface(renderedImage);
// Then convert the result back to the backbuffer format and write it back
SDL_Surface* newBackBuffer = SDL_ConvertSurface(tempBackbuffer, DDBackBuffer->format);
SDL_DestroySurface(tempBackbuffer);
SDL_BlitSurface(newBackBuffer, &srcRect, DDBackBuffer, &srcRect);
SDL_DestroySurface(newBackBuffer);
return DD_OK;
}
HRESULT ForceUpdate(int x, int y, int w, int h) override { return DD_OK; }
HRESULT Clear() override { return DD_OK; }
HRESULT SetCamera(IDirect3DRMFrame* camera) override
{
m_camera = camera;
return DD_OK;
}
HRESULT GetCamera(IDirect3DRMFrame** camera) override
{
*camera = m_camera;
return DD_OK;
}
HRESULT SetProjection(D3DRMPROJECTIONTYPE type) override { return DD_OK; }
D3DRMPROJECTIONTYPE GetProjection() override { return D3DRMPROJECTIONTYPE::PERSPECTIVE; }
HRESULT SetFront(D3DVALUE z) override { return DD_OK; }
D3DVALUE GetFront() override { return 0; }
HRESULT SetBack(D3DVALUE z) override { return DD_OK; }
D3DVALUE GetBack() override { return 0; }
HRESULT SetField(D3DVALUE field) override { return DD_OK; }
D3DVALUE GetField() override { return 0; }
int GetWidth() override { return 640; }
int GetHeight() override { return 480; }
HRESULT Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world) override { return DD_OK; }
HRESULT InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen) override { return DD_OK; }
HRESULT Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray) override { return DD_OK; }
private:
IDirect3DRMFrame* m_camera = nullptr;
};
struct Direct3DRMLightImpl : public Direct3DRMObjectBase<IDirect3DRMLight> { struct Direct3DRMLightImpl : public Direct3DRMObjectBase<IDirect3DRMLight> {
HRESULT SetColorRGB(float r, float g, float b) override { return DD_OK; } HRESULT SetColorRGB(float r, float g, float b) override { return DD_OK; }
}; };
struct Direct3DRMMaterialImpl : public Direct3DRMObjectBase<IDirect3DRMMaterial> {}; struct Direct3DRMMaterialImpl : public Direct3DRMObjectBase<IDirect3DRMMaterial> {};
SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device)
{
const SDL_GPUShaderCreateInfo* vertexCreateInfo =
GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device));
if (!vertexCreateInfo) {
return nullptr;
}
SDL_GPUShader* vertexShader = SDL_CreateGPUShader(device, vertexCreateInfo);
if (!vertexShader) {
return nullptr;
}
const SDL_GPUShaderCreateInfo* fragmentCreateInfo =
GetFragmentShaderCode(FragmentShaderId::SolidColor, SDL_GetGPUShaderFormats(device));
if (!fragmentCreateInfo) {
return nullptr;
}
SDL_GPUShader* fragmentShader = SDL_CreateGPUShader(device, fragmentCreateInfo);
if (!fragmentShader) {
return nullptr;
}
SDL_GPUVertexBufferDescription vertexBufferDescs[1] = {};
vertexBufferDescs[0].slot = 0;
vertexBufferDescs[0].pitch = sizeof(PositionColorVertex);
vertexBufferDescs[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
vertexBufferDescs[0].instance_step_rate = 0;
SDL_GPUVertexAttribute vertexAttrs[2] = {};
vertexAttrs[0].location = 0;
vertexAttrs[0].buffer_slot = 0;
vertexAttrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
vertexAttrs[0].offset = 0;
vertexAttrs[1].location = 1;
vertexAttrs[1].buffer_slot = 0;
vertexAttrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM;
vertexAttrs[1].offset = sizeof(float) * 3;
SDL_GPUVertexInputState vertexInputState = {};
vertexInputState.vertex_buffer_descriptions = vertexBufferDescs;
vertexInputState.num_vertex_buffers = 1;
vertexInputState.vertex_attributes = vertexAttrs;
vertexInputState.num_vertex_attributes = 2;
SDL_GPUColorTargetDescription colorTargets = {};
colorTargets.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB;
SDL_GPUGraphicsPipelineCreateInfo pipelineCreateInfo = {};
pipelineCreateInfo.vertex_shader = vertexShader;
pipelineCreateInfo.fragment_shader = fragmentShader;
pipelineCreateInfo.vertex_input_state = vertexInputState;
pipelineCreateInfo.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets;
pipelineCreateInfo.target_info.num_color_targets = 1;
SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo);
// Clean up shader resources
SDL_ReleaseGPUShader(device, vertexShader);
SDL_ReleaseGPUShader(device, fragmentShader);
return pipeline;
}
struct Direct3DRMImpl : virtual public IDirect3DRM2 { struct Direct3DRMImpl : virtual public IDirect3DRM2 {
// IUnknown interface // IUnknown interface
HRESULT QueryInterface(const GUID& riid, void** ppvObject) override HRESULT QueryInterface(const GUID& riid, void** ppvObject) override
@ -683,15 +289,34 @@ struct Direct3DRMImpl : virtual public IDirect3DRM2 {
*ppvObject = static_cast<IDirect3DRM2*>(this); *ppvObject = static_cast<IDirect3DRM2*>(this);
return DD_OK; return DD_OK;
} }
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "DirectDrawImpl does not implement guid"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Direct3DRMImpl does not implement guid");
return E_NOINTERFACE; return E_NOINTERFACE;
} }
// IDirect3DRM interface // IDirect3DRM interface
HRESULT CreateDevice(IDirect3DRMDevice2** outDevice, DWORD width, DWORD height)
{
SDL_GPUDevice* device = SDL_CreateGPUDevice(
SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL,
true,
NULL
);
if (device == NULL) {
return DDERR_GENERIC;
}
if (DDWindow == NULL) {
return DDERR_GENERIC;
}
if (!SDL_ClaimWindowForGPUDevice(device, DDWindow)) {
return DDERR_GENERIC;
}
*outDevice = static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl(width, height, device));
return DD_OK;
}
HRESULT CreateDeviceFromD3D(const IDirect3D2* d3d, IDirect3DDevice2* d3dDevice, IDirect3DRMDevice2** outDevice) HRESULT CreateDeviceFromD3D(const IDirect3D2* d3d, IDirect3DDevice2* d3dDevice, IDirect3DRMDevice2** outDevice)
override override
{ {
*outDevice = static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl); return CreateDevice(outDevice, 640, 480);
return DD_OK;
} }
HRESULT CreateDeviceFromSurface( HRESULT CreateDeviceFromSurface(
const GUID* guid, const GUID* guid,
@ -700,8 +325,10 @@ struct Direct3DRMImpl : virtual public IDirect3DRM2 {
IDirect3DRMDevice2** outDevice IDirect3DRMDevice2** outDevice
) override ) override
{ {
*outDevice = static_cast<IDirect3DRMDevice2*>(new Direct3DRMDevice2Impl); DDSURFACEDESC DDSDesc;
return DD_OK; DDSDesc.dwSize = sizeof(DDSURFACEDESC);
surface->GetSurfaceDesc(&DDSDesc);
return CreateDevice(outDevice, DDSDesc.dwWidth, DDSDesc.dwHeight);
} }
HRESULT CreateTexture(D3DRMIMAGE* image, IDirect3DRMTexture2** outTexture) override HRESULT CreateTexture(D3DRMIMAGE* image, IDirect3DRMTexture2** outTexture) override
{ {
@ -734,7 +361,7 @@ struct Direct3DRMImpl : virtual public IDirect3DRM2 {
return DD_OK; return DD_OK;
} }
HRESULT CreateViewport( HRESULT CreateViewport(
IDirect3DRMDevice2* device, IDirect3DRMDevice2* iDevice,
IDirect3DRMFrame* camera, IDirect3DRMFrame* camera,
int x, int x,
int y, int y,
@ -743,12 +370,49 @@ struct Direct3DRMImpl : virtual public IDirect3DRM2 {
IDirect3DRMViewport** outViewport IDirect3DRMViewport** outViewport
) override ) override
{ {
*outViewport = static_cast<IDirect3DRMViewport*>(new Direct3DRMViewportImpl); auto device = static_cast<Direct3DRMDevice2Impl*>(iDevice);
SDL_GPUGraphicsPipeline* pipeline = InitializeGraphicsPipeline(device->m_device);
if (!pipeline) {
return DDERR_GENERIC;
}
SDL_GPUTextureCreateInfo textureInfo = {};
textureInfo.type = SDL_GPU_TEXTURETYPE_2D;
textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB;
textureInfo.width = width;
textureInfo.height = height;
textureInfo.layer_count_or_depth = 1;
textureInfo.num_levels = 1;
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
SDL_GPUTexture* transferTexture = SDL_CreateGPUTexture(device->m_device, &textureInfo);
if (transferTexture == NULL) {
return DDERR_GENERIC;
}
// Setup texture GPU-to-CPU transfer
SDL_GPUTransferBufferCreateInfo downloadTransferInfo = {};
downloadTransferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
downloadTransferInfo.size = static_cast<Uint32>(width * height * 4);
SDL_GPUTransferBuffer* downloadTransferBuffer =
SDL_CreateGPUTransferBuffer(device->m_device, &downloadTransferInfo);
if (!downloadTransferBuffer) {
return DDERR_GENERIC;
}
*outViewport = static_cast<IDirect3DRMViewport*>(new Direct3DRMViewportImpl(
width,
height,
device->m_device,
transferTexture,
downloadTransferBuffer,
pipeline
));
device->AddViewport(*outViewport); device->AddViewport(*outViewport);
return DD_OK; return DD_OK;
} }
HRESULT SetDefaultTextureShades(unsigned int count) override { return DD_OK; } HRESULT SetDefaultTextureShades(DWORD count) override { return DD_OK; }
HRESULT SetDefaultTextureColors(unsigned int count) override { return DD_OK; } HRESULT SetDefaultTextureColors(DWORD count) override { return DD_OK; }
}; };
HRESULT WINAPI Direct3DRMCreate(IDirect3DRM** direct3DRM) HRESULT WINAPI Direct3DRMCreate(IDirect3DRM** direct3DRM)

View File

@ -0,0 +1,117 @@
#include "miniwin_d3drm.h"
#include "miniwin_d3drm_p.h"
#include "miniwin_d3drmobject_p.h"
#include "miniwin_d3drmviewport_p.h"
#include <SDL3/SDL.h>
Direct3DRMDevice2Impl::Direct3DRMDevice2Impl(DWORD width, DWORD height, SDL_GPUDevice* device)
: m_width(width), m_height(height), m_device(device), m_viewports(new Direct3DRMViewportArrayImpl)
{
}
Direct3DRMDevice2Impl::~Direct3DRMDevice2Impl()
{
for (int i = 0; i < m_viewports->GetSize(); i++) {
IDirect3DRMViewport* viewport;
m_viewports->GetElement(i, &viewport);
static_cast<Direct3DRMViewportImpl*>(viewport)->CloseDevice();
viewport->Release();
}
m_viewports->Release();
SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow);
SDL_DestroyGPUDevice(m_device);
}
DWORD Direct3DRMDevice2Impl::GetWidth()
{
return m_width;
}
DWORD Direct3DRMDevice2Impl::GetHeight()
{
return m_height;
}
HRESULT Direct3DRMDevice2Impl::SetBufferCount(int count)
{
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::GetBufferCount()
{
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::SetShades(DWORD shadeCount)
{
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::GetShades()
{
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::SetQuality(D3DRMRENDERQUALITY quality)
{
return DD_OK;
}
D3DRMRENDERQUALITY Direct3DRMDevice2Impl::GetQuality()
{
return D3DRMRENDERQUALITY::GOURAUD;
}
HRESULT Direct3DRMDevice2Impl::SetDither(int dither)
{
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::GetDither()
{
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::SetTextureQuality(D3DRMTEXTUREQUALITY quality)
{
return DD_OK;
}
D3DRMTEXTUREQUALITY Direct3DRMDevice2Impl::GetTextureQuality()
{
return D3DRMTEXTUREQUALITY::LINEAR;
}
HRESULT Direct3DRMDevice2Impl::SetRenderMode(D3DRMRENDERMODE mode)
{
return DD_OK;
}
D3DRMRENDERMODE Direct3DRMDevice2Impl::GetRenderMode()
{
return D3DRMRENDERMODE::BLENDEDTRANSPARENCY;
}
HRESULT Direct3DRMDevice2Impl::Update()
{
for (int i = 0; i < m_viewports->GetSize(); i++) {
IDirect3DRMViewport* viewport;
m_viewports->GetElement(i, &viewport);
static_cast<Direct3DRMViewportImpl*>(viewport)->Update();
}
return DD_OK;
}
HRESULT Direct3DRMDevice2Impl::AddViewport(IDirect3DRMViewport* viewport)
{
return m_viewports->AddElement(viewport);
}
HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewportArray)
{
*ppViewportArray = m_viewports;
return DD_OK;
}

View File

@ -0,0 +1,267 @@
#include "miniwin_d3drm_p.h"
#include "miniwin_d3drmviewport_p.h"
#include <SDL3/SDL.h>
Direct3DRMViewportImpl::Direct3DRMViewportImpl(
DWORD width,
DWORD height,
SDL_GPUDevice* device,
SDL_GPUTexture* transferTexture,
SDL_GPUTransferBuffer* downloadTransferBuffer,
SDL_GPUGraphicsPipeline* pipeline
)
: m_width(width), m_height(height), m_device(device), m_transferTexture(transferTexture),
m_downloadTransferBuffer(downloadTransferBuffer), m_pipeline(pipeline)
{
}
void Direct3DRMViewportImpl::FreeDeviceResources()
{
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_pipeline);
}
Direct3DRMViewportImpl::~Direct3DRMViewportImpl()
{
FreeDeviceResources();
}
void Direct3DRMViewportImpl::Update()
{
m_vertexCount = 3;
SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
bufferCreateInfo.size = static_cast<Uint32>(sizeof(PositionColorVertex) * m_vertexCount);
m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
SDL_GPUTransferBufferCreateInfo transferCreateInfo = {};
transferCreateInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
transferCreateInfo.size = static_cast<Uint32>(sizeof(PositionColorVertex) * m_vertexCount);
SDL_GPUTransferBuffer* transferBuffer = SDL_CreateGPUTransferBuffer(m_device, &transferCreateInfo);
PositionColorVertex* transferData =
(PositionColorVertex*) SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
transferData[0] = {-1, -1, 0, 255, 0, 0, 255};
transferData[1] = {1, -1, 0, 0, 0, 255, 255};
transferData[2] = {0, 1, 0, 0, 255, 0, 128};
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* uploadCmdBuf = SDL_AcquireGPUCommandBuffer(m_device);
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(uploadCmdBuf);
SDL_GPUTransferBufferLocation transferLocation = {};
transferLocation.transfer_buffer = transferBuffer;
transferLocation.offset = 0;
SDL_GPUBufferRegion bufferRegion = {};
bufferRegion.buffer = m_vertexBuffer;
bufferRegion.offset = 0;
bufferRegion.size = static_cast<Uint32>(sizeof(PositionColorVertex) * m_vertexCount);
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
SDL_SubmitGPUCommandBuffer(uploadCmdBuf);
SDL_ReleaseGPUTransferBuffer(m_device, transferBuffer);
m_updated = true;
}
HRESULT Direct3DRMViewportImpl::Render(IDirect3DRMFrame* group)
{
if (!m_updated) {
return DDERR_GENERIC;
}
if (!m_device) {
return DDERR_GENERIC;
}
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (cmdbuf == NULL) {
return DDERR_GENERIC;
}
// Render the graphics
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
// Make the render target transparent so we can combine it with the back buffer
colorTargetInfo.clear_color = {0, 0, 0, 0};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, NULL);
SDL_BindGPUGraphicsPipeline(renderPass, m_pipeline);
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);
// Download rendered image
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTextureRegion region = {};
region.texture = m_transferTexture;
region.w = DDBackBuffer->w;
region.h = DDBackBuffer->h;
region.d = 1;
SDL_GPUTextureTransferInfo transferInfo = {};
transferInfo.transfer_buffer = m_downloadTransferBuffer;
transferInfo.offset = 0;
SDL_DownloadFromGPUTexture(copyPass, &region, &transferInfo);
SDL_EndGPUCopyPass(copyPass);
SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdbuf);
if (!cmdbuf || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) {
return DDERR_GENERIC;
}
SDL_ReleaseGPUFence(m_device, fence);
void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadTransferBuffer, false);
if (!downloadedData) {
return DDERR_GENERIC;
}
m_updated = false;
SDL_DestroySurface(m_renderedImage);
m_renderedImage = SDL_CreateSurfaceFrom(
DDBackBuffer->w,
DDBackBuffer->h,
SDL_PIXELFORMAT_ABGR8888,
downloadedData,
DDBackBuffer->w * 4
);
SDL_Surface* convertedRender = SDL_ConvertSurface(m_renderedImage, SDL_PIXELFORMAT_RGBA8888);
SDL_DestroySurface(m_renderedImage);
SDL_UnmapGPUTransferBuffer(m_device, m_downloadTransferBuffer);
m_renderedImage = convertedRender;
return ForceUpdate(0, 0, DDBackBuffer->w, DDBackBuffer->h);
}
HRESULT Direct3DRMViewportImpl::ForceUpdate(int x, int y, int w, int h)
{
if (!m_renderedImage) {
return DDERR_GENERIC;
}
// Blit the render back to our backbuffer
SDL_Rect srcRect{0, 0, DDBackBuffer->w, DDBackBuffer->h};
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(DDBackBuffer->format);
if (details->Amask != 0) {
// Backbuffer supports transparnacy
SDL_Surface* convertedRender = SDL_ConvertSurface(m_renderedImage, DDBackBuffer->format);
SDL_DestroySurface(m_renderedImage);
m_renderedImage = convertedRender;
return DD_OK;
}
if (m_renderedImage->format == DDBackBuffer->format) {
// No conversion needed
SDL_BlitSurface(m_renderedImage, &srcRect, DDBackBuffer, &srcRect);
return DD_OK;
}
// Convert backbuffer to a format that supports transparancy
SDL_Surface* tempBackbuffer = SDL_ConvertSurface(DDBackBuffer, m_renderedImage->format);
SDL_BlitSurface(m_renderedImage, &srcRect, tempBackbuffer, &srcRect);
// Then convert the result back to the backbuffer format and write it back
SDL_Surface* newBackBuffer = SDL_ConvertSurface(tempBackbuffer, DDBackBuffer->format);
SDL_DestroySurface(tempBackbuffer);
SDL_BlitSurface(newBackBuffer, &srcRect, DDBackBuffer, &srcRect);
SDL_DestroySurface(newBackBuffer);
return DD_OK;
}
HRESULT Direct3DRMViewportImpl::Clear()
{
return DD_OK;
}
HRESULT Direct3DRMViewportImpl::SetCamera(IDirect3DRMFrame* camera)
{
m_camera = camera;
return DD_OK;
}
HRESULT Direct3DRMViewportImpl::GetCamera(IDirect3DRMFrame** camera)
{
*camera = m_camera;
return DD_OK;
}
HRESULT Direct3DRMViewportImpl::SetProjection(D3DRMPROJECTIONTYPE type)
{
return DD_OK;
}
D3DRMPROJECTIONTYPE Direct3DRMViewportImpl::GetProjection()
{
return D3DRMPROJECTIONTYPE::PERSPECTIVE;
}
HRESULT Direct3DRMViewportImpl::SetFront(D3DVALUE z)
{
return DD_OK;
}
D3DVALUE Direct3DRMViewportImpl::GetFront()
{
return 0;
}
HRESULT Direct3DRMViewportImpl::SetBack(D3DVALUE z)
{
return DD_OK;
}
D3DVALUE Direct3DRMViewportImpl::GetBack()
{
return 0;
}
HRESULT Direct3DRMViewportImpl::SetField(D3DVALUE field)
{
return DD_OK;
}
D3DVALUE Direct3DRMViewportImpl::GetField()
{
return 0;
}
DWORD Direct3DRMViewportImpl::GetWidth()
{
return m_width;
}
DWORD Direct3DRMViewportImpl::GetHeight()
{
return m_height;
}
HRESULT Direct3DRMViewportImpl::Transform(D3DRMVECTOR4D* screen, D3DVECTOR* world)
{
return DD_OK;
}
HRESULT Direct3DRMViewportImpl::InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D* screen)
{
return DD_OK;
}
HRESULT Direct3DRMViewportImpl::Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* pickedArray)
{
return DD_OK;
}
void Direct3DRMViewportImpl::CloseDevice()
{
FreeDeviceResources();
m_device = nullptr;
}

View File

@ -35,7 +35,7 @@ HRESULT DirectDrawSurfaceImpl::QueryInterface(const GUID& riid, void** ppvObject
*ppvObject = static_cast<IDirectDrawSurface3*>(this); *ppvObject = static_cast<IDirectDrawSurface3*>(this);
return S_OK; return S_OK;
} }
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "DirectDrawImpl does not implement guid"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "DirectDrawSurfaceImpl does not implement guid");
return E_NOINTERFACE; return E_NOINTERFACE;
} }