Removed dx render api and added rumble logo

This commit is contained in:
KiritoDv 2021-07-23 14:08:27 -05:00
parent 18d69ff933
commit 4ed2e05870
18 changed files with 83 additions and 2832 deletions

View File

@ -106,3 +106,25 @@ const u8 *const game_over_texture_table[] = {
};
UNUSED static const u64 title_screen_bg_unused_0 = 0;
// Texture from Ultra 64 Mario Bros. Project
ALIGNED8 static const u8 title_texture_rumble_pak[] = "textures/moon/controller/rumble_supported.rgba16";
Gfx title_screen_bg_dl_0A007548_start[] = {
gsDPPipeSync(),
gsDPSetCycleType(G_CYC_COPY),
gsDPSetTexturePersp(G_TP_NONE),
gsDPSetTextureFilter(G_TF_POINT),
gsDPSetRenderMode(G_RM_NOOP, G_RM_NOOP2),
gsDPLoadTextureTile(title_texture_rumble_pak, G_IM_FMT_RGBA, G_IM_SIZ_16b, 80, 0, 0, 0, 79, 23, 0, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, 7, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPEndDisplayList(),
};
Gfx title_screen_bg_dl_0A007548_end[] = {
gsDPPipeSync(),
gsDPSetCycleType(G_CYC_1CYCLE),
gsDPSetTexturePersp(G_TP_PERSP),
gsDPSetTextureFilter(G_TF_BILERP),
gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2),
gsSPEndDisplayList(),
};

View File

@ -91,6 +91,10 @@ const GeoLayout intro_geo_00035C[] = {
GEO_ASM(2, geo_draw_mario_head_goddard),
GEO_CLOSE_NODE(),
GEO_CLOSE_NODE(),
GEO_ZBUFFER(0),
GEO_OPEN_NODE(),
GEO_ASM(0, geo_intro_rumble_pak_graphic),
GEO_CLOSE_NODE(),
GEO_CLOSE_NODE(),
GEO_END(),
};
@ -113,6 +117,10 @@ const GeoLayout intro_geo_0003B8[] = {
GEO_ASM(3, geo_draw_mario_head_goddard),
GEO_CLOSE_NODE(),
GEO_CLOSE_NODE(),
GEO_ZBUFFER(0),
GEO_OPEN_NODE(),
GEO_ASM(0, geo_intro_rumble_pak_graphic),
GEO_CLOSE_NODE(),
GEO_CLOSE_NODE(),
GEO_END(),
};
@ -150,4 +158,3 @@ const GeoLayout intro_geo_000414[] = {
GEO_CLOSE_NODE(),
GEO_END(),
};

View File

@ -152,7 +152,7 @@ static s32 bhv_cmd_cylboard(void) {
// Command 0x1B: Sets the current model ID of the object.
// Usage: SET_MODEL(modelID)
static s32 bhv_cmd_set_model(void) {
u32 modelID = BHV_CMD_GET_U32(0);
u32 modelID = BHV_CMD_GET_2ND_S16(0);
gCurrentObject->header.gfx.sharedChild = get_graph_node(modelID);
gCurBhvCommand++;
return BHV_PROC_CONTINUE;

View File

@ -113,7 +113,7 @@ Gfx *geo_n64_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
displayListIter = displayList;
scaleX = 1.0f;
scaleY = 1.0f;
scaleZ = 1.0f;
scaleZ = 1.0f;
guScale(scaleMat, 0, scaleY, scaleZ);
guRotate(scaleMat, 10, 1, 0, 0);
guRotate(rotMat, gTitleRotationCounter, 0, 1, 0);
@ -132,7 +132,7 @@ Gfx *geo_n64_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
int range = 80;
float step = 1;
if(gTitlePos >= range)
if(gTitlePos >= range)
gTitlePingPong = 1;
else if (gTitlePos <= -range)
gTitlePingPong = 0;
@ -239,7 +239,7 @@ Gfx *intro_backdrop_one_image(s32 index, s8 *backgroundTable) {
f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO;
int num_tiles_h = (((aspect*SCREEN_HEIGHT)+79)/80);
float x_ofs = (SCREEN_WIDTH/2)-(aspect*SCREEN_HEIGHT/2);
mtx = alloc_display_list(sizeof(*mtx));
displayList = alloc_display_list(36 * sizeof(*displayList));
displayListIter = displayList;
@ -248,8 +248,8 @@ Gfx *intro_backdrop_one_image(s32 index, s8 *backgroundTable) {
gSPMatrix(displayListIter++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_PUSH);
gSPDisplayList(displayListIter++, &title_screen_bg_dl_0A000118);
for (i = 0; i < 4; ++i) {
gDPLoadTextureBlock(displayListIter++, vIntroBgTable[i], G_IM_FMT_RGBA, G_IM_SIZ_16b, 80, 20, 0,
G_TX_CLAMP, G_TX_CLAMP, 7, 6, G_TX_NOLOD, G_TX_NOLOD)
gDPLoadTextureBlock(displayListIter++, vIntroBgTable[i], G_IM_FMT_RGBA, G_IM_SIZ_16b, 80, 20, 0,
G_TX_CLAMP, G_TX_CLAMP, 7, 6, G_TX_NOLOD, G_TX_NOLOD)
gSPDisplayList(displayListIter++, introBackgroundDlRows[i]);
}
gSPPopMatrix(displayListIter++, G_MTX_MODELVIEW);
@ -271,7 +271,7 @@ Gfx *geo_intro_backdrop(s32 sp48, struct GraphNode *sp4c, UNUSED void *context)
displayListIter = NULL;
f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO;
int num_tiles_h = (((aspect*SCREEN_HEIGHT)+79)/80);
if (sp48 == 1) {
displayList = alloc_display_list(((num_tiles_h*3)+4) * sizeof(*displayList));
displayListIter = displayList;
@ -298,7 +298,7 @@ Gfx *geo_game_over_tile(s32 sp40, struct GraphNode *sp44, UNUSED void *context)
displayListIter = NULL;
f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO;
int num_tiles_h = (((aspect*SCREEN_HEIGHT)+79)/80);
if (sp40 != 1) {
gGameOverFrameCounter = 0;
gGameOverTableIndex = -2;
@ -335,3 +335,33 @@ Gfx *geo_game_over_tile(s32 sp40, struct GraphNode *sp44, UNUSED void *context)
}
return displayList;
}
extern Gfx title_screen_bg_dl_0A007548_start[];
extern Gfx title_screen_bg_dl_0A007548_end[];
Gfx *geo_intro_rumble_pak_graphic(s32 state, struct GraphNode *node, UNUSED void *context) {
struct GraphNodeGenerated *genNode = (struct GraphNodeGenerated *)node;
Gfx *dlIter;
Gfx *dl;
s32 introContext;
s8 backgroundTileSix;
u16 left;
dl = NULL;
backgroundTileSix = 0;
left = GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(100);
if (state != 1) {
dl = NULL;
} else if (state == 1) {
dl = alloc_display_list(6 * sizeof(*dl));
if (dl != NULL) {
dlIter = dl;
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A007548_start);
gSPTextureRectangle(dlIter++, left << 2, 200 << 2, (left + 79) << 2, (200 + 23) << 2, 7, 0, 0, 4 << 10, 1 << 10);
gSPDisplayList(dlIter++, &title_screen_bg_dl_0A007548_end);
gSPEndDisplayList(dlIter);
}
}
return dl;
}

View File

@ -15,4 +15,5 @@ Gfx *intro_backdrop_one_image(s32 index, s8 *backgroundTable);
Gfx *geo_intro_backdrop(s32 sp48, struct GraphNode *sp4c, UNUSED void *context);
Gfx *geo_game_over_tile(s32 sp40, struct GraphNode *sp44, UNUSED void *context);
Gfx *geo_intro_rumble_pak_graphic(s32 state, struct GraphNode *node, UNUSED void *context);
#endif // INTRO_GEO_H

View File

@ -53,10 +53,14 @@ namespace MoonInternal {
ImFontConfig font_cfg;
font_cfg.FontDataOwnedByAtlas = false;
io.Fonts->AddFontFromMemoryTTF((void*) entry->second->data, entry->second->size, 18.f, &font_cfg);
cout << "Loading font: " << entry->first << endl;
}
ImGui::StyleColorsLightGreen();
io.ConfigWindowsMoveFromTitleBarOnly = true;
MoonInternal::bindHook(IMGUI_API_INIT);
MoonInternal::initBindHook(1,
(struct HookParameter){.name = "io", .parameter = (void*) &io}
);
MoonInternal::callBindHook(0);
window = (SDL_Window*) call.baseArgs["window"];
ImGui_ImplSDL2_InitForOpenGL(window, call.baseArgs["context"]);
@ -78,16 +82,18 @@ namespace MoonInternal {
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();
static float f = 0.0f;
static int counter = 0;
MoonInternal::bindHook(IMGUI_API_DRAW);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(0);
if(showWindow){
ImGui::Begin("Moon64 Game Stats");
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Moon64 Game Stats", NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize);
ImGui::Text("Framerate: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("Branch: " GIT_BRANCH);
ImGui::Text("Commit: " GIT_HASH);
ImGui::End();
ImGui::PopStyleColor();
}
ImGui::Render();

View File

@ -14,6 +14,9 @@ struct HookParameter {
#define SAVE_GRAPH_NODE "SaveGraphNode"
#define LOAD_GRAPH_NODE "LoadGraphNode"
#define IMGUI_API_INIT "ImGuiApiInit"
#define IMGUI_API_DRAW "ImGuiApiDraw"
#define WINDOW_API_INIT "WApiInit"
#define WINDOW_API_HANDLE_EVENTS "WApiHandleEvents"

View File

@ -1,754 +0,0 @@
#ifdef RAPI_D3D11
#include <cstdio>
#include <vector>
#include <cmath>
#include <windows.h>
#include <versionhelpers.h>
#include <wrl/client.h>
#include <dxgi1_3.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#ifndef _LANGUAGE_C
#define _LANGUAGE_C
#endif
#include <PR/gbi.h>
#include "gfx_cc.h"
#include "gfx_window_manager_api.h"
#include "gfx_rendering_api.h"
#include "gfx_direct3d_common.h"
#define DECLARE_GFX_DXGI_FUNCTIONS
#include "gfx_dxgi.h"
#include "gfx_screen_config.h"
#include "moon/mod-engine/hooks/hook.h"
#define THREE_POINT_FILTERING 0
#define DEBUG_D3D 0
using namespace Microsoft::WRL; // For ComPtr
namespace {
struct PerFrameCB {
uint32_t noise_frame;
float noise_scale_x;
float noise_scale_y;
uint32_t padding;
};
struct PerDrawCB {
struct Texture {
uint32_t width;
uint32_t height;
uint32_t linear_filtering;
uint32_t padding;
} textures[2];
};
struct TextureData {
ComPtr<ID3D11ShaderResourceView> resource_view;
ComPtr<ID3D11SamplerState> sampler_state;
uint32_t width;
uint32_t height;
bool linear_filtering;
};
struct ShaderProgramD3D11 {
ComPtr<ID3D11VertexShader> vertex_shader;
ComPtr<ID3D11PixelShader> pixel_shader;
ComPtr<ID3D11InputLayout> input_layout;
ComPtr<ID3D11BlendState> blend_state;
uint32_t shader_id;
uint8_t num_inputs;
uint8_t num_floats;
bool used_textures[2];
};
static struct {
HMODULE d3d11_module;
PFN_D3D11_CREATE_DEVICE D3D11CreateDevice;
HMODULE d3dcompiler_module;
pD3DCompile D3DCompile;
D3D_FEATURE_LEVEL feature_level;
ComPtr<ID3D11Device> device;
ComPtr<IDXGISwapChain1> swap_chain;
ComPtr<ID3D11DeviceContext> context;
ComPtr<ID3D11RenderTargetView> backbuffer_view;
ComPtr<ID3D11DepthStencilView> depth_stencil_view;
ComPtr<ID3D11RasterizerState> rasterizer_state;
ComPtr<ID3D11DepthStencilState> depth_stencil_state;
ComPtr<ID3D11Buffer> vertex_buffer;
ComPtr<ID3D11Buffer> per_frame_cb;
ComPtr<ID3D11Buffer> per_draw_cb;
#if DEBUG_D3D
ComPtr<ID3D11Debug> debug;
#endif
DXGI_SAMPLE_DESC sample_description;
PerFrameCB per_frame_cb_data;
PerDrawCB per_draw_cb_data;
struct ShaderProgramD3D11 shader_program_pool[64];
uint8_t shader_program_pool_size;
std::vector<struct TextureData> textures;
int current_tile;
uint32_t current_texture_ids[2];
// Current state
struct ShaderProgramD3D11 *shader_program;
uint32_t current_width, current_height;
int8_t depth_test;
int8_t depth_mask;
int8_t zmode_decal;
// Previous states (to prevent setting states needlessly)
struct ShaderProgramD3D11 *last_shader_program = nullptr;
uint32_t last_vertex_buffer_stride = 0;
ComPtr<ID3D11BlendState> last_blend_state = nullptr;
ComPtr<ID3D11ShaderResourceView> last_resource_views[2] = { nullptr, nullptr };
ComPtr<ID3D11SamplerState> last_sampler_states[2] = { nullptr, nullptr };
int8_t last_depth_test = -1;
int8_t last_depth_mask = -1;
int8_t last_zmode_decal = -1;
D3D_PRIMITIVE_TOPOLOGY last_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
} d3d;
static LARGE_INTEGER last_time, accumulated_time, frequency;
static void create_render_target_views(bool is_resize) {
DXGI_SWAP_CHAIN_DESC1 desc1;
if (is_resize) {
// Release previous stuff (if any)
d3d.backbuffer_view.Reset();
d3d.depth_stencil_view.Reset();
// Resize swap chain buffers
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
ThrowIfFailed(d3d.swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, desc1.Flags),
gfx_dxgi_get_h_wnd(), "Failed to resize IDXGISwapChain buffers.");
}
// Get new size
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
// Create back buffer
ComPtr<ID3D11Texture2D> backbuffer_texture;
ThrowIfFailed(d3d.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *) backbuffer_texture.GetAddressOf()),
gfx_dxgi_get_h_wnd(), "Failed to get backbuffer from IDXGISwapChain.");
ThrowIfFailed(d3d.device->CreateRenderTargetView(backbuffer_texture.Get(), nullptr, d3d.backbuffer_view.GetAddressOf()),
gfx_dxgi_get_h_wnd(), "Failed to create render target view.");
// Create depth buffer
D3D11_TEXTURE2D_DESC depth_stencil_texture_desc;
ZeroMemory(&depth_stencil_texture_desc, sizeof(D3D11_TEXTURE2D_DESC));
depth_stencil_texture_desc.Width = desc1.Width;
depth_stencil_texture_desc.Height = desc1.Height;
depth_stencil_texture_desc.MipLevels = 1;
depth_stencil_texture_desc.ArraySize = 1;
depth_stencil_texture_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_D24_UNORM_S8_UINT;
depth_stencil_texture_desc.SampleDesc = d3d.sample_description;
depth_stencil_texture_desc.Usage = D3D11_USAGE_DEFAULT;
depth_stencil_texture_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depth_stencil_texture_desc.CPUAccessFlags = 0;
depth_stencil_texture_desc.MiscFlags = 0;
ComPtr<ID3D11Texture2D> depth_stencil_texture;
ThrowIfFailed(d3d.device->CreateTexture2D(&depth_stencil_texture_desc, nullptr, depth_stencil_texture.GetAddressOf()));
ThrowIfFailed(d3d.device->CreateDepthStencilView(depth_stencil_texture.Get(), nullptr, d3d.depth_stencil_view.GetAddressOf()));
// Save resolution
d3d.current_width = desc1.Width;
d3d.current_height = desc1.Height;
}
static void gfx_d3d11_init(void) {
// Load d3d11.dll
d3d.d3d11_module = LoadLibraryW(L"d3d11.dll");
if (d3d.d3d11_module == nullptr) {
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()), gfx_dxgi_get_h_wnd(), "d3d11.dll could not be loaded");
}
d3d.D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d.d3d11_module, "D3D11CreateDevice");
// Load D3DCompiler_47.dll or D3DCompiler_43.dll
d3d.d3dcompiler_module = LoadLibraryW(L"D3DCompiler_47.dll");
if (d3d.d3dcompiler_module == nullptr) {
d3d.d3dcompiler_module = LoadLibraryW(L"D3DCompiler_43.dll");
if (d3d.d3dcompiler_module == nullptr) {
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()), gfx_dxgi_get_h_wnd(), "D3DCompiler_47.dll or D3DCompiler_43.dll could not be loaded");
}
}
d3d.D3DCompile = (pD3DCompile)GetProcAddress(d3d.d3dcompiler_module, "D3DCompile");
// Create D3D11 device
gfx_dxgi_create_factory_and_device(DEBUG_D3D, 11, [](IDXGIAdapter1 *adapter, bool test_only) {
#if DEBUG_D3D
UINT device_creation_flags = D3D11_CREATE_DEVICE_DEBUG;
#else
UINT device_creation_flags = 0;
#endif
D3D_FEATURE_LEVEL FeatureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
HRESULT res = d3d.D3D11CreateDevice(
adapter,
D3D_DRIVER_TYPE_UNKNOWN, // since we use a specific adapter
nullptr,
device_creation_flags,
FeatureLevels,
ARRAYSIZE(FeatureLevels),
D3D11_SDK_VERSION,
test_only ? nullptr : d3d.device.GetAddressOf(),
&d3d.feature_level,
test_only ? nullptr : d3d.context.GetAddressOf());
if (test_only) {
return SUCCEEDED(res);
} else {
ThrowIfFailed(res, gfx_dxgi_get_h_wnd(), "Failed to create D3D11 device.");
return true;
}
});
// Sample description to be used in back buffer and depth buffer
d3d.sample_description.Count = 1;
d3d.sample_description.Quality = 0;
// Create the swap chain
d3d.swap_chain = gfx_dxgi_create_swap_chain(d3d.device.Get());
// Create D3D Debug device if in debug mode
#if DEBUG_D3D
ThrowIfFailed(d3d.device->QueryInterface(__uuidof(ID3D11Debug), (void **) d3d.debug.GetAddressOf()),
gfx_dxgi_get_h_wnd(), "Failed to get ID3D11Debug device.");
#endif
// Create views
create_render_target_views(false);
// Create main vertex buffer
D3D11_BUFFER_DESC vertex_buffer_desc;
ZeroMemory(&vertex_buffer_desc, sizeof(D3D11_BUFFER_DESC));
vertex_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
vertex_buffer_desc.ByteWidth = 256 * 26 * 3 * sizeof(float); // Same as buf_vbo size in gfx_pc
vertex_buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertex_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vertex_buffer_desc.MiscFlags = 0;
ThrowIfFailed(d3d.device->CreateBuffer(&vertex_buffer_desc, nullptr, d3d.vertex_buffer.GetAddressOf()),
gfx_dxgi_get_h_wnd(), "Failed to create vertex buffer.");
// Create per-frame constant buffer
D3D11_BUFFER_DESC constant_buffer_desc;
ZeroMemory(&constant_buffer_desc, sizeof(D3D11_BUFFER_DESC));
constant_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
constant_buffer_desc.ByteWidth = sizeof(PerFrameCB);
constant_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constant_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
constant_buffer_desc.MiscFlags = 0;
ThrowIfFailed(d3d.device->CreateBuffer(&constant_buffer_desc, nullptr, d3d.per_frame_cb.GetAddressOf()),
gfx_dxgi_get_h_wnd(), "Failed to create per-frame constant buffer.");
d3d.context->PSSetConstantBuffers(0, 1, d3d.per_frame_cb.GetAddressOf());
// Create per-draw constant buffer
constant_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
constant_buffer_desc.ByteWidth = sizeof(PerDrawCB);
constant_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constant_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
constant_buffer_desc.MiscFlags = 0;
ThrowIfFailed(d3d.device->CreateBuffer(&constant_buffer_desc, nullptr, d3d.per_draw_cb.GetAddressOf()),
gfx_dxgi_get_h_wnd(), "Failed to create per-draw constant buffer.");
d3d.context->PSSetConstantBuffers(1, 1, d3d.per_draw_cb.GetAddressOf());
MoonInternal::bindHook(GFX_INIT);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static bool gfx_d3d11_z_is_from_0_to_1(void) {
return true;
}
static void gfx_d3d11_unload_shader(struct ShaderProgram *old_prg) {
}
static void gfx_d3d11_load_shader(struct ShaderProgram *new_prg) {
d3d.shader_program = (struct ShaderProgramD3D11 *)new_prg;
}
static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint32_t shader_id) {
CCFeatures cc_features;
gfx_cc_get_features(shader_id, &cc_features);
char buf[4096];
size_t len, num_floats;
gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, THREE_POINT_FILTERING);
ComPtr<ID3DBlob> vs, ps;
ComPtr<ID3DBlob> error_blob;
#if DEBUG_D3D
UINT compile_flags = D3DCOMPILE_DEBUG;
#else
UINT compile_flags = D3DCOMPILE_OPTIMIZATION_LEVEL2;
#endif
HRESULT hr = d3d.D3DCompile(buf, len, nullptr, nullptr, nullptr, "VSMain", "vs_4_0_level_9_1", compile_flags, 0, vs.GetAddressOf(), error_blob.GetAddressOf());
if (FAILED(hr)) {
MessageBox(gfx_dxgi_get_h_wnd(), (char *) error_blob->GetBufferPointer(), "Error", MB_OK | MB_ICONERROR);
throw hr;
}
hr = d3d.D3DCompile(buf, len, nullptr, nullptr, nullptr, "PSMain", "ps_4_0_level_9_1", compile_flags, 0, ps.GetAddressOf(), error_blob.GetAddressOf());
if (FAILED(hr)) {
MessageBox(gfx_dxgi_get_h_wnd(), (char *) error_blob->GetBufferPointer(), "Error", MB_OK | MB_ICONERROR);
throw hr;
}
struct ShaderProgramD3D11 *prg = &d3d.shader_program_pool[d3d.shader_program_pool_size++];
ThrowIfFailed(d3d.device->CreateVertexShader(vs->GetBufferPointer(), vs->GetBufferSize(), nullptr, prg->vertex_shader.GetAddressOf()));
ThrowIfFailed(d3d.device->CreatePixelShader(ps->GetBufferPointer(), ps->GetBufferSize(), nullptr, prg->pixel_shader.GetAddressOf()));
// Input Layout
D3D11_INPUT_ELEMENT_DESC ied[7];
uint8_t ied_index = 0;
ied[ied_index++] = { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
ied[ied_index++] = { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
}
if (cc_features.opt_fog) {
ied[ied_index++] = { "FOG", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
}
for (unsigned int i = 0; i < cc_features.num_inputs; i++) {
DXGI_FORMAT format = cc_features.opt_alpha ? DXGI_FORMAT_R32G32B32A32_FLOAT : DXGI_FORMAT_R32G32B32_FLOAT;
ied[ied_index++] = { "INPUT", i, format, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
}
ThrowIfFailed(d3d.device->CreateInputLayout(ied, ied_index, vs->GetBufferPointer(), vs->GetBufferSize(), prg->input_layout.GetAddressOf()));
// Blend state
D3D11_BLEND_DESC blend_desc;
ZeroMemory(&blend_desc, sizeof(D3D11_BLEND_DESC));
if (cc_features.opt_alpha) {
blend_desc.RenderTarget[0].BlendEnable = true;
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
} else {
blend_desc.RenderTarget[0].BlendEnable = false;
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
}
ThrowIfFailed(d3d.device->CreateBlendState(&blend_desc, prg->blend_state.GetAddressOf()));
// Save some values
prg->shader_id = shader_id;
prg->num_inputs = cc_features.num_inputs;
prg->num_floats = num_floats;
prg->used_textures[0] = cc_features.used_textures[0];
prg->used_textures[1] = cc_features.used_textures[1];
return (struct ShaderProgram *)(d3d.shader_program = prg);
}
static struct ShaderProgram *gfx_d3d11_lookup_shader(uint32_t shader_id) {
for (size_t i = 0; i < d3d.shader_program_pool_size; i++) {
if (d3d.shader_program_pool[i].shader_id == shader_id) {
return (struct ShaderProgram *)&d3d.shader_program_pool[i];
}
}
return nullptr;
}
static void gfx_d3d11_shader_get_info(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]) {
struct ShaderProgramD3D11 *p = (struct ShaderProgramD3D11 *)prg;
*num_inputs = p->num_inputs;
used_textures[0] = p->used_textures[0];
used_textures[1] = p->used_textures[1];
}
static uint32_t gfx_d3d11_new_texture(void) {
d3d.textures.resize(d3d.textures.size() + 1);
return (uint32_t)(d3d.textures.size() - 1);
}
static void gfx_d3d11_select_texture(int tile, uint32_t texture_id) {
d3d.current_tile = tile;
d3d.current_texture_ids[tile] = texture_id;
}
static D3D11_TEXTURE_ADDRESS_MODE gfx_cm_to_d3d11(uint32_t val) {
if (val & G_TX_CLAMP) {
return D3D11_TEXTURE_ADDRESS_CLAMP;
}
return (val & G_TX_MIRROR) ? D3D11_TEXTURE_ADDRESS_MIRROR : D3D11_TEXTURE_ADDRESS_WRAP;
}
static void gfx_d3d11_upload_texture(const uint8_t *rgba32_buf, int width, int height) {
// Create texture
D3D11_TEXTURE2D_DESC texture_desc;
ZeroMemory(&texture_desc, sizeof(D3D11_TEXTURE2D_DESC));
texture_desc.Width = width;
texture_desc.Height = height;
texture_desc.Usage = D3D11_USAGE_IMMUTABLE;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0; // D3D11_RESOURCE_MISC_GENERATE_MIPS ?
texture_desc.ArraySize = 1;
texture_desc.MipLevels = 1;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
D3D11_SUBRESOURCE_DATA resource_data;
resource_data.pSysMem = rgba32_buf;
resource_data.SysMemPitch = width * 4;
resource_data.SysMemSlicePitch = resource_data.SysMemPitch * height;
ComPtr<ID3D11Texture2D> texture;
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, &resource_data, texture.GetAddressOf()));
// Create shader resource view from texture
D3D11_SHADER_RESOURCE_VIEW_DESC resource_view_desc;
ZeroMemory(&resource_view_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
resource_view_desc.Format = texture_desc.Format;
resource_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
resource_view_desc.Texture2D.MostDetailedMip = 0;
resource_view_desc.Texture2D.MipLevels = -1;
TextureData *texture_data = &d3d.textures[d3d.current_texture_ids[d3d.current_tile]];
texture_data->width = width;
texture_data->height = height;
if (texture_data->resource_view.Get() != nullptr) {
// Free the previous texture in this slot
texture_data->resource_view.Reset();
}
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), &resource_view_desc, texture_data->resource_view.GetAddressOf()));
}
static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
D3D11_SAMPLER_DESC sampler_desc;
ZeroMemory(&sampler_desc, sizeof(D3D11_SAMPLER_DESC));
#if THREE_POINT_FILTERING
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
#else
sampler_desc.Filter = linear_filter ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
#endif
sampler_desc.AddressU = gfx_cm_to_d3d11(cms);
sampler_desc.AddressV = gfx_cm_to_d3d11(cmt);
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.MinLOD = 0;
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
TextureData *texture_data = &d3d.textures[d3d.current_texture_ids[tile]];
texture_data->linear_filtering = linear_filter;
// This function is called twice per texture, the first one only to set default values.
// Maybe that could be skipped? Anyway, make sure to release the first default sampler
// state before setting the actual one.
texture_data->sampler_state.Reset();
ThrowIfFailed(d3d.device->CreateSamplerState(&sampler_desc, texture_data->sampler_state.GetAddressOf()));
}
static void gfx_d3d11_set_depth_test(bool depth_test) {
d3d.depth_test = depth_test;
}
static void gfx_d3d11_set_depth_mask(bool depth_mask) {
d3d.depth_mask = depth_mask;
}
static void gfx_d3d11_set_zmode_decal(bool zmode_decal) {
d3d.zmode_decal = zmode_decal;
}
static void gfx_d3d11_set_viewport(int x, int y, int width, int height) {
D3D11_VIEWPORT viewport;
viewport.TopLeftX = x;
viewport.TopLeftY = d3d.current_height - y - height;
viewport.Width = width;
viewport.Height = height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
d3d.context->RSSetViewports(1, &viewport);
}
static void gfx_d3d11_set_scissor(int x, int y, int width, int height) {
D3D11_RECT rect;
rect.left = x;
rect.top = d3d.current_height - y - height;
rect.right = x + width;
rect.bottom = d3d.current_height - y;
d3d.context->RSSetScissorRects(1, &rect);
}
static void gfx_d3d11_set_use_alpha(bool use_alpha) {
// Already part of the pipeline state from shader info
}
static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) {
if (d3d.last_depth_test != d3d.depth_test || d3d.last_depth_mask != d3d.depth_mask) {
d3d.last_depth_test = d3d.depth_test;
d3d.last_depth_mask = d3d.depth_mask;
d3d.depth_stencil_state.Reset();
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc;
ZeroMemory(&depth_stencil_desc, sizeof(D3D11_DEPTH_STENCIL_DESC));
depth_stencil_desc.DepthEnable = d3d.depth_test;
depth_stencil_desc.DepthWriteMask = d3d.depth_mask ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
depth_stencil_desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
depth_stencil_desc.StencilEnable = false;
ThrowIfFailed(d3d.device->CreateDepthStencilState(&depth_stencil_desc, d3d.depth_stencil_state.GetAddressOf()));
d3d.context->OMSetDepthStencilState(d3d.depth_stencil_state.Get(), 0);
}
if (d3d.last_zmode_decal != d3d.zmode_decal) {
d3d.last_zmode_decal = d3d.zmode_decal;
d3d.rasterizer_state.Reset();
D3D11_RASTERIZER_DESC rasterizer_desc;
ZeroMemory(&rasterizer_desc, sizeof(D3D11_RASTERIZER_DESC));
rasterizer_desc.FillMode = D3D11_FILL_SOLID;
rasterizer_desc.CullMode = D3D11_CULL_NONE;
rasterizer_desc.FrontCounterClockwise = true;
rasterizer_desc.DepthBias = 0;
rasterizer_desc.SlopeScaledDepthBias = d3d.zmode_decal ? -2.0f : 0.0f;
rasterizer_desc.DepthBiasClamp = 0.0f;
rasterizer_desc.DepthClipEnable = true;
rasterizer_desc.ScissorEnable = true;
rasterizer_desc.MultisampleEnable = false;
rasterizer_desc.AntialiasedLineEnable = false;
ThrowIfFailed(d3d.device->CreateRasterizerState(&rasterizer_desc, d3d.rasterizer_state.GetAddressOf()));
d3d.context->RSSetState(d3d.rasterizer_state.Get());
}
bool textures_changed = false;
for (int i = 0; i < 2; i++) {
if (d3d.shader_program->used_textures[i]) {
if (d3d.last_resource_views[i].Get() != d3d.textures[d3d.current_texture_ids[i]].resource_view.Get()) {
d3d.last_resource_views[i] = d3d.textures[d3d.current_texture_ids[i]].resource_view.Get();
d3d.context->PSSetShaderResources(i, 1, d3d.textures[d3d.current_texture_ids[i]].resource_view.GetAddressOf());
#if THREE_POINT_FILTERING
d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width;
d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height;
d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering;
textures_changed = true;
#endif
if (d3d.last_sampler_states[i].Get() != d3d.textures[d3d.current_texture_ids[i]].sampler_state.Get()) {
d3d.last_sampler_states[i] = d3d.textures[d3d.current_texture_ids[i]].sampler_state.Get();
d3d.context->PSSetSamplers(i, 1, d3d.textures[d3d.current_texture_ids[i]].sampler_state.GetAddressOf());
}
}
}
}
// Set per-draw constant buffer
if (textures_changed) {
D3D11_MAPPED_SUBRESOURCE ms;
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
d3d.context->Map(d3d.per_draw_cb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
memcpy(ms.pData, &d3d.per_draw_cb_data, sizeof(PerDrawCB));
d3d.context->Unmap(d3d.per_draw_cb.Get(), 0);
}
// Set vertex buffer data
D3D11_MAPPED_SUBRESOURCE ms;
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
d3d.context->Map(d3d.vertex_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
memcpy(ms.pData, buf_vbo, buf_vbo_len * sizeof(float));
d3d.context->Unmap(d3d.vertex_buffer.Get(), 0);
uint32_t stride = d3d.shader_program->num_floats * sizeof(float);
uint32_t offset = 0;
if (d3d.last_vertex_buffer_stride != stride) {
d3d.last_vertex_buffer_stride = stride;
d3d.context->IASetVertexBuffers(0, 1, d3d.vertex_buffer.GetAddressOf(), &stride, &offset);
}
if (d3d.last_shader_program != d3d.shader_program) {
d3d.last_shader_program = d3d.shader_program;
d3d.context->IASetInputLayout(d3d.shader_program->input_layout.Get());
d3d.context->VSSetShader(d3d.shader_program->vertex_shader.Get(), 0, 0);
d3d.context->PSSetShader(d3d.shader_program->pixel_shader.Get(), 0, 0);
if (d3d.last_blend_state.Get() != d3d.shader_program->blend_state.Get()) {
d3d.last_blend_state = d3d.shader_program->blend_state.Get();
d3d.context->OMSetBlendState(d3d.shader_program->blend_state.Get(), 0, 0xFFFFFFFF);
}
}
if (d3d.last_primitive_topology != D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST) {
d3d.last_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
d3d.context->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
d3d.context->Draw(buf_vbo_num_tris * 3, 0);
}
static void gfx_d3d11_on_resize(void) {
create_render_target_views(true);
MoonInternal::bindHook(GFX_ON_REZISE);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static void gfx_d3d11_start_frame(void) {
MoonInternal::bindHook(GFX_PRE_START_FRAME);
MoonInternal::initBindHook(0);
if(MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d})) return;
// Set render targets
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
// Clear render targets
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
d3d.context->ClearRenderTargetView(d3d.backbuffer_view.Get(), clearColor);
d3d.context->ClearDepthStencilView(d3d.depth_stencil_view.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
// Set per-frame constant buffer
d3d.per_frame_cb_data.noise_frame++;
if (d3d.per_frame_cb_data.noise_frame > 150) {
// No high values, as noise starts to look ugly
d3d.per_frame_cb_data.noise_frame = 0;
}
d3d.per_frame_cb_data.noise_scale_x = (float) d3d.current_width;
d3d.per_frame_cb_data.noise_scale_y = (float) d3d.current_height;
D3D11_MAPPED_SUBRESOURCE ms;
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
d3d.context->Map(d3d.per_frame_cb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
memcpy(ms.pData, &d3d.per_frame_cb_data, sizeof(PerFrameCB));
d3d.context->Unmap(d3d.per_frame_cb.Get(), 0);
MoonInternal::bindHook(GFX_POST_START_FRAME);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static void gfx_d3d11_end_frame(void) {
MoonInternal::bindHook(GFX_PRE_END_FRAME);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
MoonInternal::bindHook(GFX_POST_END_FRAME);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static void gfx_d3d11_finish_render(void) {
}
} // namespace
struct GfxRenderingAPI gfx_direct3d11_api = {
gfx_d3d11_z_is_from_0_to_1,
gfx_d3d11_unload_shader,
gfx_d3d11_load_shader,
gfx_d3d11_create_and_load_new_shader,
gfx_d3d11_lookup_shader,
gfx_d3d11_shader_get_info,
gfx_d3d11_new_texture,
gfx_d3d11_select_texture,
gfx_d3d11_upload_texture,
gfx_d3d11_set_sampler_parameters,
gfx_d3d11_set_depth_test,
gfx_d3d11_set_depth_mask,
gfx_d3d11_set_zmode_decal,
gfx_d3d11_set_viewport,
gfx_d3d11_set_scissor,
gfx_d3d11_set_use_alpha,
gfx_d3d11_draw_triangles,
gfx_d3d11_init,
gfx_d3d11_on_resize,
gfx_d3d11_start_frame,
gfx_d3d11_end_frame,
gfx_d3d11_finish_render
};
#endif

View File

@ -1,12 +0,0 @@
#ifdef RAPI_D3D11
#ifndef GFX_DIRECT3D11_H
#define GFX_DIRECT3D11_H
#include "gfx_rendering_api.h"
extern struct GfxRenderingAPI gfx_direct3d11_api;
#endif
#endif

View File

@ -1,990 +0,0 @@
#ifdef RAPI_D3D12
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <map>
#include <set>
#include <vector>
#include <windows.h>
#include <wrl/client.h>
// This is needed when compiling with MinGW, used in d3d12.h
#define __in_ecount_opt(size)
#include <dxgi.h>
#include <dxgi1_4.h>
#include "dxsdk/d3d12.h"
#include <d3dcompiler.h>
#include "gfx_direct3d12_guids.h"
#include "dxsdk/d3dx12.h"
#ifndef _LANGUAGE_C
#define _LANGUAGE_C
#endif
#include <PR/gbi.h>
#define DECLARE_GFX_DXGI_FUNCTIONS
#include "gfx_dxgi.h"
#include "gfx_cc.h"
#include "gfx_window_manager_api.h"
#include "gfx_rendering_api.h"
#include "gfx_direct3d_common.h"
#include "gfx_screen_config.h"
#include "moon/mod-engine/hooks/hook.h"
#define DEBUG_D3D 0
using namespace Microsoft::WRL; // For ComPtr
namespace {
struct ShaderProgramD3D12 {
uint32_t shader_id;
uint8_t num_inputs;
bool used_textures[2];
uint8_t num_floats;
uint8_t num_attribs;
ComPtr<ID3DBlob> vertex_shader;
ComPtr<ID3DBlob> pixel_shader;
ComPtr<ID3D12RootSignature> root_signature;
};
struct PipelineDesc {
uint32_t shader_id;
bool depth_test;
bool depth_mask;
bool zmode_decal;
bool _padding;
bool operator==(const PipelineDesc& o) const {
return memcmp(this, &o, sizeof(*this)) == 0;
}
bool operator<(const PipelineDesc& o) const {
return memcmp(this, &o, sizeof(*this)) < 0;
}
};
struct TextureHeap {
ComPtr<ID3D12Heap> heap;
std::vector<uint8_t> free_list;
};
struct TextureData {
ComPtr<ID3D12Resource> resource;
struct TextureHeap *heap;
uint8_t heap_offset;
uint64_t last_frame_counter;
uint32_t descriptor_index;
int sampler_parameters;
};
struct NoiseCB {
uint32_t noise_frame;
float noise_scale_x;
float noise_scale_y;
uint32_t padding;
};
static struct {
HMODULE d3d12_module;
PFN_D3D12_CREATE_DEVICE D3D12CreateDevice;
PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface;
HMODULE d3dcompiler_module;
pD3DCompile D3DCompile;
struct ShaderProgramD3D12 shader_program_pool[64];
uint8_t shader_program_pool_size;
uint32_t current_width, current_height;
ComPtr<ID3D12Device> device;
ComPtr<ID3D12CommandQueue> command_queue;
ComPtr<ID3D12CommandQueue> copy_command_queue;
ComPtr<IDXGISwapChain3> swap_chain;
ComPtr<ID3D12DescriptorHeap> rtv_heap;
UINT rtv_descriptor_size;
ComPtr<ID3D12Resource> render_targets[2];
ComPtr<ID3D12CommandAllocator> command_allocator;
ComPtr<ID3D12CommandAllocator> copy_command_allocator;
ComPtr<ID3D12GraphicsCommandList> command_list;
ComPtr<ID3D12GraphicsCommandList> copy_command_list;
ComPtr<ID3D12DescriptorHeap> dsv_heap;
ComPtr<ID3D12Resource> depth_stencil_buffer;
ComPtr<ID3D12DescriptorHeap> srv_heap;
UINT srv_descriptor_size;
ComPtr<ID3D12DescriptorHeap> sampler_heap;
UINT sampler_descriptor_size;
std::map<std::pair<uint32_t, uint32_t>, std::list<struct TextureHeap>> texture_heaps;
std::map<size_t, std::vector<ComPtr<ID3D12Resource>>> upload_heaps;
std::vector<std::pair<size_t, ComPtr<ID3D12Resource>>> upload_heaps_in_flight;
ComPtr<ID3D12Fence> copy_fence;
uint64_t copy_fence_value;
std::vector<struct TextureData> textures;
int current_tile;
uint32_t current_texture_ids[2];
uint32_t srv_pos;
int frame_index;
ComPtr<ID3D12Fence> fence;
HANDLE fence_event;
uint64_t frame_counter;
ComPtr<ID3D12Resource> noise_cb;
void *mapped_noise_cb_address;
struct NoiseCB noise_cb_data;
ComPtr<ID3D12Resource> vertex_buffer;
void *mapped_vbuf_address;
int vbuf_pos;
std::vector<ComPtr<ID3D12Resource>> resources_to_clean_at_end_of_frame;
std::vector<std::pair<struct TextureHeap *, uint8_t>> texture_heap_allocations_to_reclaim_at_end_of_frame;
std::map<PipelineDesc, ComPtr<ID3D12PipelineState>> pipeline_states;
bool must_reload_pipeline;
// Current state:
ID3D12PipelineState *pipeline_state;
struct ShaderProgramD3D12 *shader_program;
bool depth_test;
bool depth_mask;
bool zmode_decal;
CD3DX12_VIEWPORT viewport;
CD3DX12_RECT scissor;
} d3d;
static int texture_uploads = 0;
static int max_texture_uploads;
static D3D12_CPU_DESCRIPTOR_HANDLE get_cpu_descriptor_handle(ComPtr<ID3D12DescriptorHeap>& heap) {
#ifdef __MINGW32__
// We would like to do this:
// D3D12_CPU_DESCRIPTOR_HANDLE handle = heap->GetCPUDescriptorHandleForHeapStart();
// but MinGW64 doesn't follow the calling conventions of VC++ for some reason.
// Per MS documentation "User-defined types can be returned by value from global functions and static member functions"...
// "Otherwise, the caller assumes the responsibility of allocating memory and passing a pointer for the return value as the first argument".
// The method here is a non-static member function, and hence we need to pass the address to the return value as a parameter.
// MinGW32 has the same issue.
auto fn = heap->GetCPUDescriptorHandleForHeapStart;
void (STDMETHODCALLTYPE ID3D12DescriptorHeap::*fun)(D3D12_CPU_DESCRIPTOR_HANDLE *out) = (void (STDMETHODCALLTYPE ID3D12DescriptorHeap::*)(D3D12_CPU_DESCRIPTOR_HANDLE *out))fn;
D3D12_CPU_DESCRIPTOR_HANDLE handle;
(heap.Get()->*fun)(&handle);
return handle;
#else
return heap->GetCPUDescriptorHandleForHeapStart();
#endif
}
static D3D12_GPU_DESCRIPTOR_HANDLE get_gpu_descriptor_handle(ComPtr<ID3D12DescriptorHeap>& heap) {
#ifdef __MINGW32__
// See get_cpu_descriptor_handle
auto fn = heap->GetGPUDescriptorHandleForHeapStart;
void (STDMETHODCALLTYPE ID3D12DescriptorHeap::*fun)(D3D12_GPU_DESCRIPTOR_HANDLE *out) = (void (STDMETHODCALLTYPE ID3D12DescriptorHeap::*)(D3D12_GPU_DESCRIPTOR_HANDLE *out))fn;
D3D12_GPU_DESCRIPTOR_HANDLE handle;
(heap.Get()->*fun)(&handle);
return handle;
#else
return heap->GetGPUDescriptorHandleForHeapStart();
#endif
}
static D3D12_RESOURCE_ALLOCATION_INFO get_resource_allocation_info(const D3D12_RESOURCE_DESC *resource_desc) {
#ifdef __MINGW32__
// See get_cpu_descriptor_handle
auto fn = d3d.device->GetResourceAllocationInfo;
void (STDMETHODCALLTYPE ID3D12Device::*fun)(D3D12_RESOURCE_ALLOCATION_INFO *out, UINT visibleMask, UINT numResourceDescs, const D3D12_RESOURCE_DESC *pResourceDescs) =
(void (STDMETHODCALLTYPE ID3D12Device::*)(D3D12_RESOURCE_ALLOCATION_INFO *out, UINT visibleMask, UINT numResourceDescs, const D3D12_RESOURCE_DESC *pResourceDescs))fn;
D3D12_RESOURCE_ALLOCATION_INFO out;
(d3d.device.Get()->*fun)(&out, 0, 1, resource_desc);
return out;
#else
return d3d.device->GetResourceAllocationInfo(0, 1, resource_desc);
#endif
}
static bool gfx_direct3d12_z_is_from_0_to_1(void) {
return true;
}
static void gfx_direct3d12_unload_shader(struct ShaderProgram *old_prg) {
}
static void gfx_direct3d12_load_shader(struct ShaderProgram *new_prg) {
d3d.shader_program = (struct ShaderProgramD3D12 *)new_prg;
d3d.must_reload_pipeline = true;
}
static struct ShaderProgram *gfx_direct3d12_create_and_load_new_shader(uint32_t shader_id) {
/*static FILE *fp;
if (!fp) {
fp = fopen("shaders.txt", "w");
}
fprintf(fp, "0x%08x\n", shader_id);
fflush(fp);*/
struct ShaderProgramD3D12 *prg = &d3d.shader_program_pool[d3d.shader_program_pool_size++];
CCFeatures cc_features;
gfx_cc_get_features(shader_id, &cc_features);
char buf[2048];
size_t len, num_floats;
gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, true, false);
//fwrite(buf, 1, len, stdout);
ThrowIfFailed(d3d.D3DCompile(buf, len, nullptr, nullptr, nullptr, "VSMain", "vs_5_1", D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &prg->vertex_shader, nullptr));
ThrowIfFailed(d3d.D3DCompile(buf, len, nullptr, nullptr, nullptr, "PSMain", "ps_5_1", D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &prg->pixel_shader, nullptr));
ThrowIfFailed(d3d.device->CreateRootSignature(0, prg->pixel_shader->GetBufferPointer(), prg->pixel_shader->GetBufferSize(), IID_PPV_ARGS(&prg->root_signature)));
prg->shader_id = shader_id;
prg->num_inputs = cc_features.num_inputs;
prg->used_textures[0] = cc_features.used_textures[0];
prg->used_textures[1] = cc_features.used_textures[1];
prg->num_floats = num_floats;
//prg->num_attribs = cnt;
d3d.must_reload_pipeline = true;
return (struct ShaderProgram *)(d3d.shader_program = prg);
}
static struct ShaderProgram *gfx_direct3d12_lookup_shader(uint32_t shader_id) {
for (size_t i = 0; i < d3d.shader_program_pool_size; i++) {
if (d3d.shader_program_pool[i].shader_id == shader_id) {
return (struct ShaderProgram *)&d3d.shader_program_pool[i];
}
}
return nullptr;
}
static void gfx_direct3d12_shader_get_info(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]) {
struct ShaderProgramD3D12 *p = (struct ShaderProgramD3D12 *)prg;
*num_inputs = p->num_inputs;
used_textures[0] = p->used_textures[0];
used_textures[1] = p->used_textures[1];
}
static uint32_t gfx_direct3d12_new_texture(void) {
d3d.textures.resize(d3d.textures.size() + 1);
return (uint32_t)(d3d.textures.size() - 1);
}
static void gfx_direct3d12_select_texture(int tile, uint32_t texture_id) {
d3d.current_tile = tile;
d3d.current_texture_ids[tile] = texture_id;
}
static void gfx_direct3d12_upload_texture(const uint8_t *rgba32_buf, int width, int height) {
texture_uploads++;
ComPtr<ID3D12Resource> texture_resource;
// Describe and create a Texture2D.
D3D12_RESOURCE_DESC texture_desc = {};
texture_desc.MipLevels = 1;
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texture_desc.Width = width;
texture_desc.Height = height;
texture_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
texture_desc.DepthOrArraySize = 1;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
texture_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
texture_desc.Alignment = ((width + 31) / 32) * ((height + 31) / 32) > 16 ? 0 : D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
D3D12_RESOURCE_ALLOCATION_INFO alloc_info = get_resource_allocation_info(&texture_desc);
std::list<struct TextureHeap>& heaps = d3d.texture_heaps[std::pair<uint32_t, uint32_t>(alloc_info.SizeInBytes, alloc_info.Alignment)];
struct TextureHeap *found_heap = nullptr;
for (struct TextureHeap& heap : heaps) {
if (!heap.free_list.empty()) {
found_heap = &heap;
}
}
if (found_heap == nullptr) {
heaps.resize(heaps.size() + 1);
found_heap = &heaps.back();
// In case of HD textures, make sure too much memory isn't wasted
int textures_per_heap = 524288 / alloc_info.SizeInBytes;
if (textures_per_heap < 1) {
textures_per_heap = 1;
} else if (textures_per_heap > 64) {
textures_per_heap = 64;
}
D3D12_HEAP_DESC heap_desc = {};
heap_desc.SizeInBytes = alloc_info.SizeInBytes * textures_per_heap;
if (alloc_info.Alignment == D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT) {
heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
} else {
heap_desc.Alignment = alloc_info.Alignment;
}
heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heap_desc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heap_desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT;
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
ThrowIfFailed(d3d.device->CreateHeap(&heap_desc, IID_PPV_ARGS(&found_heap->heap)));
for (int i = 0; i < textures_per_heap; i++) {
found_heap->free_list.push_back(i);
}
}
uint8_t heap_offset = found_heap->free_list.back();
found_heap->free_list.pop_back();
ThrowIfFailed(d3d.device->CreatePlacedResource(found_heap->heap.Get(), heap_offset * alloc_info.SizeInBytes, &texture_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&texture_resource)));
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
UINT num_rows;
UINT64 row_size_in_bytes;
UINT64 upload_buffer_size;
d3d.device->GetCopyableFootprints(&texture_desc, 0, 1, 0, &layout, &num_rows, &row_size_in_bytes, &upload_buffer_size);
std::vector<ComPtr<ID3D12Resource>>& upload_heaps = d3d.upload_heaps[upload_buffer_size];
ComPtr<ID3D12Resource> upload_heap;
if (upload_heaps.empty()) {
CD3DX12_HEAP_PROPERTIES hp(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC rdb = CD3DX12_RESOURCE_DESC::Buffer(upload_buffer_size);
ThrowIfFailed(d3d.device->CreateCommittedResource(
&hp,
D3D12_HEAP_FLAG_NONE,
&rdb,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&upload_heap)));
} else {
upload_heap = upload_heaps.back();
upload_heaps.pop_back();
}
{
D3D12_SUBRESOURCE_DATA texture_data = {};
texture_data.pData = rgba32_buf;
texture_data.RowPitch = width * 4; // RGBA
texture_data.SlicePitch = texture_data.RowPitch * height;
void *data;
upload_heap->Map(0, nullptr, &data);
D3D12_MEMCPY_DEST dest_data = { (uint8_t *)data + layout.Offset, layout.Footprint.RowPitch, SIZE_T(layout.Footprint.RowPitch) * SIZE_T(num_rows) };
MemcpySubresource(&dest_data, &texture_data, static_cast<SIZE_T>(row_size_in_bytes), num_rows, layout.Footprint.Depth);
upload_heap->Unmap(0, nullptr);
CD3DX12_TEXTURE_COPY_LOCATION dst(texture_resource.Get(), 0);
CD3DX12_TEXTURE_COPY_LOCATION src(upload_heap.Get(), layout);
d3d.copy_command_list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
}
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(texture_resource.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
d3d.command_list->ResourceBarrier(1, &barrier);
d3d.upload_heaps_in_flight.push_back(std::make_pair((size_t)upload_buffer_size, std::move(upload_heap)));
struct TextureData& td = d3d.textures[d3d.current_texture_ids[d3d.current_tile]];
if (td.resource.Get() != nullptr) {
d3d.resources_to_clean_at_end_of_frame.push_back(std::move(td.resource));
d3d.texture_heap_allocations_to_reclaim_at_end_of_frame.push_back(std::make_pair(td.heap, td.heap_offset));
td.last_frame_counter = 0;
}
td.resource = std::move(texture_resource);
td.heap = found_heap;
td.heap_offset = heap_offset;
}
static int gfx_cm_to_index(uint32_t val) {
if (val & G_TX_CLAMP) {
return 2;
}
return (val & G_TX_MIRROR) ? 1 : 0;
}
static void gfx_direct3d12_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
d3d.textures[d3d.current_texture_ids[tile]].sampler_parameters = linear_filter * 9 + gfx_cm_to_index(cms) * 3 + gfx_cm_to_index(cmt);
}
static void gfx_direct3d12_set_depth_test(bool depth_test) {
d3d.depth_test = depth_test;
d3d.must_reload_pipeline = true;
}
static void gfx_direct3d12_set_depth_mask(bool z_upd) {
d3d.depth_mask = z_upd;
d3d.must_reload_pipeline = true;
}
static void gfx_direct3d12_set_zmode_decal(bool zmode_decal) {
d3d.zmode_decal = zmode_decal;
d3d.must_reload_pipeline = true;
}
static void gfx_direct3d12_set_viewport(int x, int y, int width, int height) {
d3d.viewport = CD3DX12_VIEWPORT(x, d3d.current_height - y - height, width, height);
}
static void gfx_direct3d12_set_scissor(int x, int y, int width, int height) {
d3d.scissor = CD3DX12_RECT(x, d3d.current_height - y - height, x + width, d3d.current_height - y);
}
static void gfx_direct3d12_set_use_alpha(bool use_alpha) {
// Already part of the pipeline state from shader info
}
static void gfx_direct3d12_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) {
struct ShaderProgramD3D12 *prg = d3d.shader_program;
if (d3d.must_reload_pipeline) {
ComPtr<ID3D12PipelineState>& pipeline_state = d3d.pipeline_states[PipelineDesc{
prg->shader_id,
d3d.depth_test,
d3d.depth_mask,
d3d.zmode_decal,
0
}];
if (pipeline_state.Get() == nullptr) {
D3D12_INPUT_ELEMENT_DESC ied[7] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
};
uint32_t ied_pos = 1;
if (prg->used_textures[0] || prg->used_textures[1]) {
ied[ied_pos++] = D3D12_INPUT_ELEMENT_DESC{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0};
}
if (prg->shader_id & SHADER_OPT_FOG) {
ied[ied_pos++] = D3D12_INPUT_ELEMENT_DESC{"FOG", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0};
}
for (int i = 0; i < prg->num_inputs; i++) {
DXGI_FORMAT format = (prg->shader_id & SHADER_OPT_ALPHA) ? DXGI_FORMAT_R32G32B32A32_FLOAT : DXGI_FORMAT_R32G32B32_FLOAT;
ied[ied_pos++] = D3D12_INPUT_ELEMENT_DESC{"INPUT", (UINT)i, format, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0};
}
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {};
desc.InputLayout = { ied, ied_pos };
desc.pRootSignature = prg->root_signature.Get();
desc.VS = CD3DX12_SHADER_BYTECODE(prg->vertex_shader.Get());
desc.PS = CD3DX12_SHADER_BYTECODE(prg->pixel_shader.Get());
desc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
if (d3d.zmode_decal) {
desc.RasterizerState.SlopeScaledDepthBias = -2.0f;
}
desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
if (prg->shader_id & SHADER_OPT_ALPHA) {
D3D12_BLEND_DESC bd = {};
bd.AlphaToCoverageEnable = FALSE;
bd.IndependentBlendEnable = FALSE;
static const D3D12_RENDER_TARGET_BLEND_DESC default_rtbd = {
TRUE, FALSE,
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
D3D12_BLEND_ONE, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
D3D12_LOGIC_OP_NOOP,
D3D12_COLOR_WRITE_ENABLE_ALL
};
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) {
bd.RenderTarget[i] = default_rtbd;
}
desc.BlendState = bd;
} else {
desc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
}
desc.DepthStencilState.DepthEnable = d3d.depth_test;
desc.DepthStencilState.DepthWriteMask = d3d.depth_mask ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
desc.DSVFormat = d3d.depth_test ? DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_UNKNOWN;
desc.SampleMask = UINT_MAX;
desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
desc.NumRenderTargets = 1;
desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
ThrowIfFailed(d3d.device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pipeline_state)));
}
d3d.pipeline_state = pipeline_state.Get();
d3d.must_reload_pipeline = false;
}
d3d.command_list->SetGraphicsRootSignature(prg->root_signature.Get());
d3d.command_list->SetPipelineState(d3d.pipeline_state);
ID3D12DescriptorHeap *heaps[] = { d3d.srv_heap.Get(), d3d.sampler_heap.Get() };
d3d.command_list->SetDescriptorHeaps(2, heaps);
int root_param_index = 0;
if ((prg->shader_id & (SHADER_OPT_ALPHA | SHADER_OPT_NOISE)) == (SHADER_OPT_ALPHA | SHADER_OPT_NOISE)) {
d3d.command_list->SetGraphicsRootConstantBufferView(root_param_index++, d3d.noise_cb->GetGPUVirtualAddress());
}
for (int i = 0; i < 2; i++) {
if (prg->used_textures[i]) {
struct TextureData& td = d3d.textures[d3d.current_texture_ids[i]];
if (td.last_frame_counter != d3d.frame_counter) {
td.descriptor_index = d3d.srv_pos;
td.last_frame_counter = d3d.frame_counter;
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = 1;
CD3DX12_CPU_DESCRIPTOR_HANDLE srv_handle(get_cpu_descriptor_handle(d3d.srv_heap), d3d.srv_pos++, d3d.srv_descriptor_size);
d3d.device->CreateShaderResourceView(td.resource.Get(), &srv_desc, srv_handle);
}
CD3DX12_GPU_DESCRIPTOR_HANDLE srv_gpu_handle(get_gpu_descriptor_handle(d3d.srv_heap), td.descriptor_index, d3d.srv_descriptor_size);
d3d.command_list->SetGraphicsRootDescriptorTable(root_param_index++, srv_gpu_handle);
CD3DX12_GPU_DESCRIPTOR_HANDLE sampler_gpu_handle(get_gpu_descriptor_handle(d3d.sampler_heap), td.sampler_parameters, d3d.sampler_descriptor_size);
d3d.command_list->SetGraphicsRootDescriptorTable(root_param_index++, sampler_gpu_handle);
}
}
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(get_cpu_descriptor_handle(d3d.rtv_heap), d3d.frame_index, d3d.rtv_descriptor_size);
D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = get_cpu_descriptor_handle(d3d.dsv_heap);
d3d.command_list->OMSetRenderTargets(1, &rtv_handle, FALSE, &dsv_handle);
d3d.command_list->RSSetViewports(1, &d3d.viewport);
d3d.command_list->RSSetScissorRects(1, &d3d.scissor);
int current_pos = d3d.vbuf_pos;
memcpy((uint8_t *)d3d.mapped_vbuf_address + current_pos, buf_vbo, buf_vbo_len * sizeof(float));
d3d.vbuf_pos += buf_vbo_len * sizeof(float);
static int maxpos;
if (d3d.vbuf_pos > maxpos) {
maxpos = d3d.vbuf_pos;
//printf("NEW MAXPOS: %d\n", maxpos);
}
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
vertex_buffer_view.BufferLocation = d3d.vertex_buffer->GetGPUVirtualAddress() + current_pos;
vertex_buffer_view.StrideInBytes = buf_vbo_len / (3 * buf_vbo_num_tris) * sizeof(float);
vertex_buffer_view.SizeInBytes = buf_vbo_len * sizeof(float);
d3d.command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3d.command_list->IASetVertexBuffers(0, 1, &vertex_buffer_view);
d3d.command_list->DrawInstanced(3 * buf_vbo_num_tris, 1, 0, 0);
}
static void gfx_direct3d12_start_frame(void) {
MoonInternal::bindHook(GFX_PRE_START_FRAME);
MoonInternal::initBindHook(0);
if(MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d})) return;
++d3d.frame_counter;
d3d.srv_pos = 0;
texture_uploads = 0;
ThrowIfFailed(d3d.command_allocator->Reset());
ThrowIfFailed(d3d.command_list->Reset(d3d.command_allocator.Get(), nullptr));
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
d3d.render_targets[d3d.frame_index].Get(),
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET);
d3d.command_list->ResourceBarrier(1, &barrier);
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(get_cpu_descriptor_handle(d3d.rtv_heap), d3d.frame_index, d3d.rtv_descriptor_size);
D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = get_cpu_descriptor_handle(d3d.dsv_heap);
d3d.command_list->OMSetRenderTargets(1, &rtv_handle, FALSE, &dsv_handle);
static unsigned char c;
const float clear_color[] = { 0.0f, 0.0f, 0.0f, 1.0f };
d3d.command_list->ClearRenderTargetView(rtv_handle, clear_color, 0, nullptr);
d3d.command_list->ClearDepthStencilView(dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
d3d.noise_cb_data.noise_frame++;
if (d3d.noise_cb_data.noise_frame > 150) {
// No high values, as noise starts to look ugly
d3d.noise_cb_data.noise_frame = 0;
}
float aspect_ratio = (float) d3d.current_width / (float) d3d.current_height;
d3d.noise_cb_data.noise_scale_x = 120 * aspect_ratio; // 120 = N64 height resolution (240) / 2
d3d.noise_cb_data.noise_scale_y = 120;
memcpy(d3d.mapped_noise_cb_address, &d3d.noise_cb_data, sizeof(struct NoiseCB));
d3d.vbuf_pos = 0;
MoonInternal::bindHook(GFX_POST_START_FRAME);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static void create_render_target_views(void) {
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = get_cpu_descriptor_handle(d3d.rtv_heap);
for (UINT i = 0; i < 2; i++) {
ThrowIfFailed(d3d.swap_chain->GetBuffer(i, IID_ID3D12Resource, (void **)&d3d.render_targets[i]));
d3d.device->CreateRenderTargetView(d3d.render_targets[i].Get(), nullptr, rtv_handle);
rtv_handle.ptr += d3d.rtv_descriptor_size;
}
}
static void create_depth_buffer(void) {
DXGI_SWAP_CHAIN_DESC1 desc1;
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
UINT width = desc1.Width;
UINT height = desc1.Height;
d3d.current_width = width;
d3d.current_height = height;
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
dsv_desc.Format = DXGI_FORMAT_D32_FLOAT;
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsv_desc.Flags = D3D12_DSV_FLAG_NONE;
D3D12_CLEAR_VALUE depth_optimized_cv = {};
depth_optimized_cv.Format = DXGI_FORMAT_D32_FLOAT;
depth_optimized_cv.DepthStencil.Depth = 1.0f;
D3D12_HEAP_PROPERTIES hp = {};
hp.Type = D3D12_HEAP_TYPE_DEFAULT;
hp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
hp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
hp.CreationNodeMask = 1;
hp.VisibleNodeMask = 1;
D3D12_RESOURCE_DESC rd = {};
rd.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
rd.Alignment = 0;
rd.Width = width;
rd.Height = height;
rd.DepthOrArraySize = 1;
rd.MipLevels = 0;
rd.Format = DXGI_FORMAT_D32_FLOAT;
rd.SampleDesc.Count = 1;
rd.SampleDesc.Quality = 0;
rd.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
rd.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
ThrowIfFailed(d3d.device->CreateCommittedResource(&hp, D3D12_HEAP_FLAG_NONE, &rd, D3D12_RESOURCE_STATE_DEPTH_WRITE, &depth_optimized_cv, IID_PPV_ARGS(&d3d.depth_stencil_buffer)));
d3d.device->CreateDepthStencilView(d3d.depth_stencil_buffer.Get(), &dsv_desc, get_cpu_descriptor_handle(d3d.dsv_heap));
}
static void gfx_direct3d12_on_resize(void) {
if (d3d.render_targets[0].Get() != nullptr) {
d3d.render_targets[0].Reset();
d3d.render_targets[1].Reset();
ThrowIfFailed(d3d.swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT));
d3d.frame_index = d3d.swap_chain->GetCurrentBackBufferIndex();
create_render_target_views();
create_depth_buffer();
MoonInternal::bindHook(GFX_ON_REZISE);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
}
static void gfx_direct3d12_init(void ) {
// Load d3d12.dll
d3d.d3d12_module = LoadLibraryW(L"d3d12.dll");
if (d3d.d3d12_module == nullptr) {
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()), gfx_dxgi_get_h_wnd(), "d3d12.dll could not be loaded");
}
d3d.D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(d3d.d3d12_module, "D3D12CreateDevice");
#if DEBUG_D3D
d3d.D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(d3d.d3d12_module, "D3D12GetDebugInterface");
#endif
// Load D3DCompiler_47.dll
d3d.d3dcompiler_module = LoadLibraryW(L"D3DCompiler_47.dll");
if (d3d.d3dcompiler_module == nullptr) {
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()), gfx_dxgi_get_h_wnd(), "D3DCompiler_47.dll could not be loaded");
}
d3d.D3DCompile = (pD3DCompile)GetProcAddress(d3d.d3dcompiler_module, "D3DCompile");
// Create device
{
UINT debug_flags = 0;
#if DEBUG_D3D
ComPtr<ID3D12Debug> debug_controller;
if (SUCCEEDED(d3d.D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller)))) {
debug_controller->EnableDebugLayer();
debug_flags |= DXGI_CREATE_FACTORY_DEBUG;
}
#endif
gfx_dxgi_create_factory_and_device(DEBUG_D3D, 12, [](IDXGIAdapter1 *adapter, bool test_only) {
HRESULT res = d3d.D3D12CreateDevice(
adapter,
D3D_FEATURE_LEVEL_11_0,
IID_ID3D12Device,
test_only ? nullptr : IID_PPV_ARGS_Helper(&d3d.device));
if (test_only) {
return SUCCEEDED(res);
} else {
ThrowIfFailed(res, gfx_dxgi_get_h_wnd(), "Failed to create D3D12 device.");
return true;
}
});
}
// Create command queues
{
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ThrowIfFailed(d3d.device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&d3d.command_queue)));
}
{
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_COPY;
ThrowIfFailed(d3d.device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&d3d.copy_command_queue)));
}
// Create swap chain
{
ComPtr<IDXGISwapChain1> swap_chain1 = gfx_dxgi_create_swap_chain(d3d.command_queue.Get());
ThrowIfFailed(swap_chain1->QueryInterface(__uuidof(IDXGISwapChain3), &d3d.swap_chain));
d3d.frame_index = d3d.swap_chain->GetCurrentBackBufferIndex();
}
// Create render target views
{
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = {};
rtv_heap_desc.NumDescriptors = 2;
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ThrowIfFailed(d3d.device->CreateDescriptorHeap(&rtv_heap_desc, IID_PPV_ARGS(&d3d.rtv_heap)));
d3d.rtv_descriptor_size = d3d.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
create_render_target_views();
}
// Create Z-buffer
{
D3D12_DESCRIPTOR_HEAP_DESC dsv_heap_desc = {};
dsv_heap_desc.NumDescriptors = 1;
dsv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
dsv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ThrowIfFailed(d3d.device->CreateDescriptorHeap(&dsv_heap_desc, IID_PPV_ARGS(&d3d.dsv_heap)));
create_depth_buffer();
}
// Create SRV heap for texture descriptors
{
D3D12_DESCRIPTOR_HEAP_DESC srv_heap_desc = {};
srv_heap_desc.NumDescriptors = 1024; // Max unique textures per frame
srv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(d3d.device->CreateDescriptorHeap(&srv_heap_desc, IID_PPV_ARGS(&d3d.srv_heap)));
d3d.srv_descriptor_size = d3d.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
// Create sampler heap and descriptors
{
D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc = {};
sampler_heap_desc.NumDescriptors = 18;
sampler_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
sampler_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(d3d.device->CreateDescriptorHeap(&sampler_heap_desc, IID_PPV_ARGS(&d3d.sampler_heap)));
d3d.sampler_descriptor_size = d3d.device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
static const D3D12_TEXTURE_ADDRESS_MODE address_modes[] = {
D3D12_TEXTURE_ADDRESS_MODE_WRAP,
D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
D3D12_TEXTURE_ADDRESS_MODE_CLAMP
};
D3D12_CPU_DESCRIPTOR_HANDLE sampler_handle = get_cpu_descriptor_handle(d3d.sampler_heap);
int pos = 0;
for (int linear_filter = 0; linear_filter < 2; linear_filter++) {
for (int cms = 0; cms < 3; cms++) {
for (int cmt = 0; cmt < 3; cmt++) {
D3D12_SAMPLER_DESC sampler_desc = {};
sampler_desc.Filter = linear_filter ? D3D12_FILTER_MIN_MAG_MIP_LINEAR : D3D12_FILTER_MIN_MAG_MIP_POINT;
sampler_desc.AddressU = address_modes[cms];
sampler_desc.AddressV = address_modes[cmt];
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
sampler_desc.MinLOD = 0;
sampler_desc.MaxLOD = D3D12_FLOAT32_MAX;
sampler_desc.MipLODBias = 0.0f;
sampler_desc.MaxAnisotropy = 1;
sampler_desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
d3d.device->CreateSampler(&sampler_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(sampler_handle, pos++, d3d.sampler_descriptor_size));
}
}
}
}
// Create constant buffer view for noise
{
/*D3D12_DESCRIPTOR_HEAP_DESC cbv_heap_desc = {};
cbv_heap_desc.NumDescriptors = 1;
cbv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(d3d.device->CreateDescriptorHeap*/
CD3DX12_HEAP_PROPERTIES hp(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC rdb = CD3DX12_RESOURCE_DESC::Buffer(256);
ThrowIfFailed(d3d.device->CreateCommittedResource(
&hp,
D3D12_HEAP_FLAG_NONE,
&rdb,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&d3d.noise_cb)));
CD3DX12_RANGE read_range(0, 0); // Read not possible from CPU
ThrowIfFailed(d3d.noise_cb->Map(0, &read_range, &d3d.mapped_noise_cb_address));
}
ThrowIfFailed(d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&d3d.command_allocator)));
ThrowIfFailed(d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&d3d.copy_command_allocator)));
ThrowIfFailed(d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d.command_allocator.Get(), nullptr, IID_PPV_ARGS(&d3d.command_list)));
ThrowIfFailed(d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, d3d.copy_command_allocator.Get(), nullptr, IID_PPV_ARGS(&d3d.copy_command_list)));
ThrowIfFailed(d3d.command_list->Close());
ThrowIfFailed(d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d.fence)));
d3d.fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (d3d.fence_event == nullptr) {
ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
}
ThrowIfFailed(d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d.copy_fence)));
{
// Create a buffer of 1 MB in size. With a 120 star speed run 192 kB seems to be max usage.
CD3DX12_HEAP_PROPERTIES hp(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC rdb = CD3DX12_RESOURCE_DESC::Buffer(256 * 1024 * sizeof(float));
ThrowIfFailed(d3d.device->CreateCommittedResource(
&hp,
D3D12_HEAP_FLAG_NONE,
&rdb,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&d3d.vertex_buffer)));
CD3DX12_RANGE read_range(0, 0); // Read not possible from CPU
ThrowIfFailed(d3d.vertex_buffer->Map(0, &read_range, &d3d.mapped_vbuf_address));
}
MoonInternal::bindHook(GFX_INIT);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static void gfx_direct3d12_end_frame(void) {
MoonInternal::bindHook(GFX_PRE_END_FRAME);
MoonInternal::initBindHook(0);
if(MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d})) return;
if (max_texture_uploads < texture_uploads && texture_uploads != 38 && texture_uploads != 34 && texture_uploads != 29) {
max_texture_uploads = texture_uploads;
}
//printf("Texture uploads: %d %d\n", max_texture_uploads, texture_uploads);
texture_uploads = 0;
ThrowIfFailed(d3d.copy_command_list->Close());
{
ID3D12CommandList *lists[] = { d3d.copy_command_list.Get() };
d3d.copy_command_queue->ExecuteCommandLists(1, lists);
d3d.copy_command_queue->Signal(d3d.copy_fence.Get(), ++d3d.copy_fence_value);
}
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
d3d.render_targets[d3d.frame_index].Get(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT);
d3d.command_list->ResourceBarrier(1, &barrier);
d3d.command_queue->Wait(d3d.copy_fence.Get(), d3d.copy_fence_value);
ThrowIfFailed(d3d.command_list->Close());
{
ID3D12CommandList *lists[] = { d3d.command_list.Get() };
d3d.command_queue->ExecuteCommandLists(1, lists);
}
{
LARGE_INTEGER t0;
QueryPerformanceCounter(&t0);
//printf("Present: %llu %u\n", (unsigned long long)(t0.QuadPart - d3d.qpc_init), d3d.length_in_vsync_frames);
}
MoonInternal::bindHook(GFX_POST_END_FRAME);
MoonInternal::initBindHook(0);
MoonInternal::callBindHook(1, (struct HookParameter){.name = "d3d", .parameter = (void*) &d3d});
}
static void gfx_direct3d12_finish_render(void) {
LARGE_INTEGER t0, t1, t2;
QueryPerformanceCounter(&t0);
static UINT64 fence_value;
ThrowIfFailed(d3d.command_queue->Signal(d3d.fence.Get(), ++fence_value));
if (d3d.fence->GetCompletedValue() < fence_value) {
ThrowIfFailed(d3d.fence->SetEventOnCompletion(fence_value, d3d.fence_event));
WaitForSingleObject(d3d.fence_event, INFINITE);
}
QueryPerformanceCounter(&t1);
d3d.resources_to_clean_at_end_of_frame.clear();
for (std::pair<size_t, ComPtr<ID3D12Resource>>& heap : d3d.upload_heaps_in_flight) {
d3d.upload_heaps[heap.first].push_back(std::move(heap.second));
}
d3d.upload_heaps_in_flight.clear();
for (std::pair<struct TextureHeap *, uint8_t>& item : d3d.texture_heap_allocations_to_reclaim_at_end_of_frame) {
item.first->free_list.push_back(item.second);
}
d3d.texture_heap_allocations_to_reclaim_at_end_of_frame.clear();
QueryPerformanceCounter(&t2);
d3d.frame_index = d3d.swap_chain->GetCurrentBackBufferIndex();
ThrowIfFailed(d3d.copy_command_allocator->Reset());
ThrowIfFailed(d3d.copy_command_list->Reset(d3d.copy_command_allocator.Get(), nullptr));
//printf("done %llu gpu:%d wait:%d freed:%llu frame:%u %u monitor:%u t:%llu\n", (unsigned long long)(t0.QuadPart - d3d.qpc_init), (int)(t1.QuadPart - t0.QuadPart), (int)(t2.QuadPart - t0.QuadPart), (unsigned long long)(t2.QuadPart - d3d.qpc_init), d3d.pending_frame_stats.rbegin()->first, stats.PresentCount, stats.SyncRefreshCount, (unsigned long long)(stats.SyncQPCTime.QuadPart - d3d.qpc_init));
}
} // namespace
struct GfxRenderingAPI gfx_direct3d12_api = {
gfx_direct3d12_z_is_from_0_to_1,
gfx_direct3d12_unload_shader,
gfx_direct3d12_load_shader,
gfx_direct3d12_create_and_load_new_shader,
gfx_direct3d12_lookup_shader,
gfx_direct3d12_shader_get_info,
gfx_direct3d12_new_texture,
gfx_direct3d12_select_texture,
gfx_direct3d12_upload_texture,
gfx_direct3d12_set_sampler_parameters,
gfx_direct3d12_set_depth_test,
gfx_direct3d12_set_depth_mask,
gfx_direct3d12_set_zmode_decal,
gfx_direct3d12_set_viewport,
gfx_direct3d12_set_scissor,
gfx_direct3d12_set_use_alpha,
gfx_direct3d12_draw_triangles,
gfx_direct3d12_init,
gfx_direct3d12_on_resize,
gfx_direct3d12_start_frame,
gfx_direct3d12_end_frame,
gfx_direct3d12_finish_render
};
#endif

View File

@ -1,12 +0,0 @@
#ifdef RAPI_D3D12
#ifndef GFX_DIRECT3D12_H
#define GFX_DIRECT3D12_H
#include "gfx_rendering_api.h"
extern struct GfxRenderingAPI gfx_direct3d12_api;
#endif
#endif

View File

@ -1,62 +0,0 @@
#ifndef GFX_DIRECT3D12_GUIDS_H
#define GFX_DIRECT3D12_GUIDS_H
#ifdef __MINGW32__
// This file is only needed due to missing MinGW-specific headers for d3d12.h.
// It will define IID_* symbols having the "selectany" attribute (assuming
// d3d12.h was earlier included), as well as make __uuidof(...) work.
#define DEF_GUID(type,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
__CRT_UUID_DECL(type,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const GUID IID_##type = __uuidof(type)
DEF_GUID(ID3D12Object,0xc4fec28f,0x7966,0x4e95,0x9f,0x94,0xf4,0x31,0xcb,0x56,0xc3,0xb8);
DEF_GUID(ID3D12DeviceChild,0x905db94b,0xa00c,0x4140,0x9d,0xf5,0x2b,0x64,0xca,0x9e,0xa3,0x57);
DEF_GUID(ID3D12RootSignature,0xc54a6b66,0x72df,0x4ee8,0x8b,0xe5,0xa9,0x46,0xa1,0x42,0x92,0x14);
DEF_GUID(ID3D12RootSignatureDeserializer,0x34AB647B,0x3CC8,0x46AC,0x84,0x1B,0xC0,0x96,0x56,0x45,0xC0,0x46);
DEF_GUID(ID3D12VersionedRootSignatureDeserializer,0x7F91CE67,0x090C,0x4BB7,0xB7,0x8E,0xED,0x8F,0xF2,0xE3,0x1D,0xA0);
DEF_GUID(ID3D12Pageable,0x63ee58fb,0x1268,0x4835,0x86,0xda,0xf0,0x08,0xce,0x62,0xf0,0xd6);
DEF_GUID(ID3D12Heap,0x6b3b2502,0x6e51,0x45b3,0x90,0xee,0x98,0x84,0x26,0x5e,0x8d,0xf3);
DEF_GUID(ID3D12Resource,0x696442be,0xa72e,0x4059,0xbc,0x79,0x5b,0x5c,0x98,0x04,0x0f,0xad);
DEF_GUID(ID3D12CommandAllocator,0x6102dee4,0xaf59,0x4b09,0xb9,0x99,0xb4,0x4d,0x73,0xf0,0x9b,0x24);
DEF_GUID(ID3D12Fence,0x0a753dcf,0xc4d8,0x4b91,0xad,0xf6,0xbe,0x5a,0x60,0xd9,0x5a,0x76);
DEF_GUID(ID3D12Fence1,0x433685fe,0xe22b,0x4ca0,0xa8,0xdb,0xb5,0xb4,0xf4,0xdd,0x0e,0x4a);
DEF_GUID(ID3D12PipelineState,0x765a30f3,0xf624,0x4c6f,0xa8,0x28,0xac,0xe9,0x48,0x62,0x24,0x45);
DEF_GUID(ID3D12DescriptorHeap,0x8efb471d,0x616c,0x4f49,0x90,0xf7,0x12,0x7b,0xb7,0x63,0xfa,0x51);
DEF_GUID(ID3D12QueryHeap,0x0d9658ae,0xed45,0x469e,0xa6,0x1d,0x97,0x0e,0xc5,0x83,0xca,0xb4);
DEF_GUID(ID3D12CommandSignature,0xc36a797c,0xec80,0x4f0a,0x89,0x85,0xa7,0xb2,0x47,0x50,0x82,0xd1);
DEF_GUID(ID3D12CommandList,0x7116d91c,0xe7e4,0x47ce,0xb8,0xc6,0xec,0x81,0x68,0xf4,0x37,0xe5);
DEF_GUID(ID3D12GraphicsCommandList,0x5b160d0f,0xac1b,0x4185,0x8b,0xa8,0xb3,0xae,0x42,0xa5,0xa4,0x55);
DEF_GUID(ID3D12GraphicsCommandList1,0x553103fb,0x1fe7,0x4557,0xbb,0x38,0x94,0x6d,0x7d,0x0e,0x7c,0xa7);
DEF_GUID(ID3D12GraphicsCommandList2,0x38C3E585,0xFF17,0x412C,0x91,0x50,0x4F,0xC6,0xF9,0xD7,0x2A,0x28);
DEF_GUID(ID3D12CommandQueue,0x0ec870a6,0x5d7e,0x4c22,0x8c,0xfc,0x5b,0xaa,0xe0,0x76,0x16,0xed);
DEF_GUID(ID3D12Device,0x189819f1,0x1db6,0x4b57,0xbe,0x54,0x18,0x21,0x33,0x9b,0x85,0xf7);
DEF_GUID(ID3D12PipelineLibrary,0xc64226a8,0x9201,0x46af,0xb4,0xcc,0x53,0xfb,0x9f,0xf7,0x41,0x4f);
DEF_GUID(ID3D12PipelineLibrary1,0x80eabf42,0x2568,0x4e5e,0xbd,0x82,0xc3,0x7f,0x86,0x96,0x1d,0xc3);
DEF_GUID(ID3D12Device1,0x77acce80,0x638e,0x4e65,0x88,0x95,0xc1,0xf2,0x33,0x86,0x86,0x3e);
DEF_GUID(ID3D12Device2,0x30baa41e,0xb15b,0x475c,0xa0,0xbb,0x1a,0xf5,0xc5,0xb6,0x43,0x28);
DEF_GUID(ID3D12Device3,0x81dadc15,0x2bad,0x4392,0x93,0xc5,0x10,0x13,0x45,0xc4,0xaa,0x98);
DEF_GUID(ID3D12ProtectedSession,0xA1533D18,0x0AC1,0x4084,0x85,0xB9,0x89,0xA9,0x61,0x16,0x80,0x6B);
DEF_GUID(ID3D12ProtectedResourceSession,0x6CD696F4,0xF289,0x40CC,0x80,0x91,0x5A,0x6C,0x0A,0x09,0x9C,0x3D);
DEF_GUID(ID3D12Device4,0xe865df17,0xa9ee,0x46f9,0xa4,0x63,0x30,0x98,0x31,0x5a,0xa2,0xe5);
DEF_GUID(ID3D12LifetimeOwner,0xe667af9f,0xcd56,0x4f46,0x83,0xce,0x03,0x2e,0x59,0x5d,0x70,0xa8);
DEF_GUID(ID3D12SwapChainAssistant,0xf1df64b6,0x57fd,0x49cd,0x88,0x07,0xc0,0xeb,0x88,0xb4,0x5c,0x8f);
DEF_GUID(ID3D12LifetimeTracker,0x3fd03d36,0x4eb1,0x424a,0xa5,0x82,0x49,0x4e,0xcb,0x8b,0xa8,0x13);
DEF_GUID(ID3D12StateObject,0x47016943,0xfca8,0x4594,0x93,0xea,0xaf,0x25,0x8b,0x55,0x34,0x6d);
DEF_GUID(ID3D12StateObjectProperties,0xde5fa827,0x9bf9,0x4f26,0x89,0xff,0xd7,0xf5,0x6f,0xde,0x38,0x60);
DEF_GUID(ID3D12Device5,0x8b4f173b,0x2fea,0x4b80,0x8f,0x58,0x43,0x07,0x19,0x1a,0xb9,0x5d);
DEF_GUID(ID3D12DeviceRemovedExtendedDataSettings,0x82BC481C,0x6B9B,0x4030,0xAE,0xDB,0x7E,0xE3,0xD1,0xDF,0x1E,0x63);
DEF_GUID(ID3D12DeviceRemovedExtendedData,0x98931D33,0x5AE8,0x4791,0xAA,0x3C,0x1A,0x73,0xA2,0x93,0x4E,0x71);
DEF_GUID(ID3D12Device6,0xc70b221b,0x40e4,0x4a17,0x89,0xaf,0x02,0x5a,0x07,0x27,0xa6,0xdc);
DEF_GUID(ID3D12Resource1,0x9D5E227A,0x4430,0x4161,0x88,0xB3,0x3E,0xCA,0x6B,0xB1,0x6E,0x19);
DEF_GUID(ID3D12Heap1,0x572F7389,0x2168,0x49E3,0x96,0x93,0xD6,0xDF,0x58,0x71,0xBF,0x6D);
DEF_GUID(ID3D12GraphicsCommandList3,0x6FDA83A7,0xB84C,0x4E38,0x9A,0xC8,0xC7,0xBD,0x22,0x01,0x6B,0x3D);
DEF_GUID(ID3D12MetaCommand,0xDBB84C27,0x36CE,0x4FC9,0xB8,0x01,0xF0,0x48,0xC4,0x6A,0xC5,0x70);
DEF_GUID(ID3D12GraphicsCommandList4,0x8754318e,0xd3a9,0x4541,0x98,0xcf,0x64,0x5b,0x50,0xdc,0x48,0x74);
DEF_GUID(ID3D12Tools,0x7071e1f0,0xe84b,0x4b33,0x97,0x4f,0x12,0xfa,0x49,0xde,0x65,0xc5);
DEF_GUID(ID3D12GraphicsCommandList5,0x55050859,0x4024,0x474c,0x87,0xf5,0x64,0x72,0xea,0xee,0x44,0xea);
#endif
#endif

View File

@ -1,313 +0,0 @@
#if defined(RAPI_D3D11) || defined(RAPI_D3D12)
#include <cstdio>
#include "gfx_direct3d_common.h"
#include "gfx_cc.h"
void get_cc_features(uint32_t shader_id, CCFeatures *cc_features) {
for (int i = 0; i < 4; i++) {
cc_features->c[0][i] = (shader_id >> (i * 3)) & 7;
cc_features->c[1][i] = (shader_id >> (12 + i * 3)) & 7;
}
cc_features->opt_alpha = (shader_id & SHADER_OPT_ALPHA) != 0;
cc_features->opt_fog = (shader_id & SHADER_OPT_FOG) != 0;
cc_features->opt_texture_edge = (shader_id & SHADER_OPT_TEXTURE_EDGE) != 0;
cc_features->opt_noise = (shader_id & SHADER_OPT_NOISE) != 0;
cc_features->used_textures[0] = false;
cc_features->used_textures[1] = false;
cc_features->num_inputs = 0;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
if (cc_features->c[i][j] >= SHADER_INPUT_1 && cc_features->c[i][j] <= SHADER_INPUT_4) {
if (cc_features->c[i][j] > cc_features->num_inputs) {
cc_features->num_inputs = cc_features->c[i][j];
}
}
if (cc_features->c[i][j] == SHADER_TEXEL0 || cc_features->c[i][j] == SHADER_TEXEL0A) {
cc_features->used_textures[0] = true;
}
if (cc_features->c[i][j] == SHADER_TEXEL1) {
cc_features->used_textures[1] = true;
}
}
}
cc_features->do_single[0] = cc_features->c[0][2] == 0;
cc_features->do_single[1] = cc_features->c[1][2] == 0;
cc_features->do_multiply[0] = cc_features->c[0][1] == 0 && cc_features->c[0][3] == 0;
cc_features->do_multiply[1] = cc_features->c[1][1] == 0 && cc_features->c[1][3] == 0;
cc_features->do_mix[0] = cc_features->c[0][1] == cc_features->c[0][3];
cc_features->do_mix[1] = cc_features->c[1][1] == cc_features->c[1][3];
cc_features->color_alpha_same = (shader_id & 0xfff) == ((shader_id >> 12) & 0xfff);
}
static void append_str(char *buf, size_t *len, const char *str) {
while (*str != '\0') buf[(*len)++] = *str++;
}
static void append_line(char *buf, size_t *len, const char *str) {
while (*str != '\0') buf[(*len)++] = *str++;
buf[(*len)++] = '\r';
buf[(*len)++] = '\n';
}
static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_alpha, bool inputs_have_alpha, bool hint_single_element) {
if (!only_alpha) {
switch (item) {
default:
case SHADER_0:
return with_alpha ? "float4(0.0, 0.0, 0.0, 0.0)" : "float3(0.0, 0.0, 0.0)";
case SHADER_INPUT_1:
return with_alpha || !inputs_have_alpha ? "input.input1" : "input.input1.rgb";
case SHADER_INPUT_2:
return with_alpha || !inputs_have_alpha ? "input.input2" : "input.input2.rgb";
case SHADER_INPUT_3:
return with_alpha || !inputs_have_alpha ? "input.input3" : "input.input3.rgb";
case SHADER_INPUT_4:
return with_alpha || !inputs_have_alpha ? "input.input4" : "input.input4.rgb";
case SHADER_TEXEL0:
return with_alpha ? "texVal0" : "texVal0.rgb";
case SHADER_TEXEL0A:
return hint_single_element ? "texVal0.a" : (with_alpha ? "float4(texVal0.a, texVal0.a, texVal0.a, texVal0.a)" : "float3(texVal0.a, texVal0.a, texVal0.a)");
case SHADER_TEXEL1:
return with_alpha ? "texVal1" : "texVal1.rgb";
}
} else {
switch (item) {
default:
case SHADER_0:
return "0.0";
case SHADER_INPUT_1:
return "input.input1.a";
case SHADER_INPUT_2:
return "input.input2.a";
case SHADER_INPUT_3:
return "input.input3.a";
case SHADER_INPUT_4:
return "input.input4.a";
case SHADER_TEXEL0:
return "texVal0.a";
case SHADER_TEXEL0A:
return "texVal0.a";
case SHADER_TEXEL1:
return "texVal1.a";
}
}
}
static void append_formula(char *buf, size_t *len, const uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) {
if (do_single) {
append_str(buf, len, shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false));
} else if (do_multiply) {
append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false));
append_str(buf, len, " * ");
append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true));
} else if (do_mix) {
append_str(buf, len, "lerp(");
append_str(buf, len, shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false));
append_str(buf, len, ", ");
append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false));
append_str(buf, len, ", ");
append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true));
append_str(buf, len, ")");
} else {
append_str(buf, len, "(");
append_str(buf, len, shader_item_to_str(c[only_alpha][0], with_alpha, only_alpha, opt_alpha, false));
append_str(buf, len, " - ");
append_str(buf, len, shader_item_to_str(c[only_alpha][1], with_alpha, only_alpha, opt_alpha, false));
append_str(buf, len, ") * ");
append_str(buf, len, shader_item_to_str(c[only_alpha][2], with_alpha, only_alpha, opt_alpha, true));
append_str(buf, len, " + ");
append_str(buf, len, shader_item_to_str(c[only_alpha][3], with_alpha, only_alpha, opt_alpha, false));
}
}
void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_floats, const CCFeatures& cc_features, bool include_root_signature, bool three_point_filtering) {
len = 0;
num_floats = 4;
// Pixel shader input struct
if (include_root_signature) {
append_str(buf, &len, "#define RS \"RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS)");
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_str(buf, &len, ",CBV(b0, visibility = SHADER_VISIBILITY_PIXEL)");
}
if (cc_features.used_textures[0]) {
append_str(buf, &len, ",DescriptorTable(SRV(t0), visibility = SHADER_VISIBILITY_PIXEL)");
append_str(buf, &len, ",DescriptorTable(Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL)");
}
if (cc_features.used_textures[1]) {
append_str(buf, &len, ",DescriptorTable(SRV(t1), visibility = SHADER_VISIBILITY_PIXEL)");
append_str(buf, &len, ",DescriptorTable(Sampler(s1), visibility = SHADER_VISIBILITY_PIXEL)");
}
append_line(buf, &len, "\"");
}
append_line(buf, &len, "struct PSInput {");
append_line(buf, &len, " float4 position : SV_POSITION;");
if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
append_line(buf, &len, " float2 uv : TEXCOORD;");
num_floats += 2;
}
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, " float4 screenPos : TEXCOORD1;");
}
if (cc_features.opt_fog) {
append_line(buf, &len, " float4 fog : FOG;");
num_floats += 4;
}
for (int i = 0; i < cc_features.num_inputs; i++) {
len += sprintf(buf + len, " float%d input%d : INPUT%d;\r\n", cc_features.opt_alpha ? 4 : 3, i + 1, i);
num_floats += cc_features.opt_alpha ? 4 : 3;
}
append_line(buf, &len, "};");
// Textures and samplers
if (cc_features.used_textures[0]) {
append_line(buf, &len, "Texture2D g_texture0 : register(t0);");
append_line(buf, &len, "SamplerState g_sampler0 : register(s0);");
}
if (cc_features.used_textures[1]) {
append_line(buf, &len, "Texture2D g_texture1 : register(t1);");
append_line(buf, &len, "SamplerState g_sampler1 : register(s1);");
}
// Constant buffer and random function
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, "cbuffer PerFrameCB : register(b0) {");
append_line(buf, &len, " uint noise_frame;");
append_line(buf, &len, " float2 noise_scale;");
append_line(buf, &len, "}");
append_line(buf, &len, "float random(in float3 value) {");
append_line(buf, &len, " float random = dot(value, float3(12.9898, 78.233, 37.719));");
append_line(buf, &len, " return frac(sin(random) * 143758.5453);");
append_line(buf, &len, "}");
}
// 3 point texture filtering
// Original author: ArthurCarvalho
// Based on GLSL implementation by twinaphex, mupen64plus-libretro project.
if (three_point_filtering && (cc_features.used_textures[0] || cc_features.used_textures[1])) {
append_line(buf, &len, "cbuffer PerDrawCB : register(b1) {");
append_line(buf, &len, " struct {");
append_line(buf, &len, " uint width;");
append_line(buf, &len, " uint height;");
append_line(buf, &len, " bool linear_filtering;");
append_line(buf, &len, " } textures[2];");
append_line(buf, &len, "}");
append_line(buf, &len, "#define TEX_OFFSET(tex, tSampler, texCoord, off, texSize) tex.Sample(tSampler, texCoord - off / texSize)");
append_line(buf, &len, "float4 tex2D3PointFilter(in Texture2D tex, in SamplerState tSampler, in float2 texCoord, in float2 texSize) {");
append_line(buf, &len, " float2 offset = frac(texCoord * texSize - float2(0.5, 0.5));");
append_line(buf, &len, " offset -= step(1.0, offset.x + offset.y);");
append_line(buf, &len, " float4 c0 = TEX_OFFSET(tex, tSampler, texCoord, offset, texSize);");
append_line(buf, &len, " float4 c1 = TEX_OFFSET(tex, tSampler, texCoord, float2(offset.x - sign(offset.x), offset.y), texSize);");
append_line(buf, &len, " float4 c2 = TEX_OFFSET(tex, tSampler, texCoord, float2(offset.x, offset.y - sign(offset.y)), texSize);");
append_line(buf, &len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
append_line(buf, &len, "}");
}
// Vertex shader
append_str(buf, &len, "PSInput VSMain(float4 position : POSITION");
if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
append_str(buf, &len, ", float2 uv : TEXCOORD");
}
if (cc_features.opt_fog) {
append_str(buf, &len, ", float4 fog : FOG");
}
for (int i = 0; i < cc_features.num_inputs; i++) {
len += sprintf(buf + len, ", float%d input%d : INPUT%d", cc_features.opt_alpha ? 4 : 3, i + 1, i);
}
append_line(buf, &len, ") {");
append_line(buf, &len, " PSInput result;");
append_line(buf, &len, " result.position = position;");
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, " result.screenPos = position;");
}
if (cc_features.used_textures[0] || cc_features.used_textures[1]) {
append_line(buf, &len, " result.uv = uv;");
}
if (cc_features.opt_fog) {
append_line(buf, &len, " result.fog = fog;");
}
for (int i = 0; i < cc_features.num_inputs; i++) {
len += sprintf(buf + len, " result.input%d = input%d;\r\n", i + 1, i + 1);
}
append_line(buf, &len, " return result;");
append_line(buf, &len, "}");
// Pixel shader
if (include_root_signature) {
append_line(buf, &len, "[RootSignature(RS)]");
}
append_line(buf, &len, "float4 PSMain(PSInput input) : SV_TARGET {");
if (cc_features.used_textures[0]) {
if (three_point_filtering) {
append_line(buf, &len, " float4 texVal0;");
append_line(buf, &len, " if (textures[0].linear_filtering)");
append_line(buf, &len, " texVal0 = tex2D3PointFilter(g_texture0, g_sampler0, input.uv, float2(textures[0].width, textures[0].height));");
append_line(buf, &len, " else");
append_line(buf, &len, " texVal0 = g_texture0.Sample(g_sampler0, input.uv);");
} else {
append_line(buf, &len, " float4 texVal0 = g_texture0.Sample(g_sampler0, input.uv);");
}
}
if (cc_features.used_textures[1]) {
if (three_point_filtering) {
append_line(buf, &len, " float4 texVal1;");
append_line(buf, &len, " if (textures[1].linear_filtering)");
append_line(buf, &len, " texVal1 = tex2D3PointFilter(g_texture1, g_sampler1, input.uv, float2(textures[1].width, textures[1].height));");
append_line(buf, &len, " else");
append_line(buf, &len, " texVal1 = g_texture1.Sample(g_sampler1, input.uv);");
} else {
append_line(buf, &len, " float4 texVal1 = g_texture1.Sample(g_sampler1, input.uv);");
}
}
append_str(buf, &len, cc_features.opt_alpha ? " float4 texel = " : " float3 texel = ");
if (!cc_features.color_alpha_same && cc_features.opt_alpha) {
append_str(buf, &len, "float4(");
append_formula(buf, &len, cc_features.c, cc_features.do_single[0], cc_features.do_multiply[0], cc_features.do_mix[0], false, false, true);
append_str(buf, &len, ", ");
append_formula(buf, &len, cc_features.c, cc_features.do_single[1], cc_features.do_multiply[1], cc_features.do_mix[1], true, true, true);
append_str(buf, &len, ")");
} else {
append_formula(buf, &len, cc_features.c, cc_features.do_single[0], cc_features.do_multiply[0], cc_features.do_mix[0], cc_features.opt_alpha, false, cc_features.opt_alpha);
}
append_line(buf, &len, ";");
if (cc_features.opt_texture_edge && cc_features.opt_alpha) {
append_line(buf, &len, " if (texel.a > 0.3) texel.a = 1.0; else discard;");
}
// TODO discard if alpha is 0?
if (cc_features.opt_fog) {
if (cc_features.opt_alpha) {
append_line(buf, &len, " texel = float4(lerp(texel.rgb, input.fog.rgb, input.fog.a), texel.a);");
} else {
append_line(buf, &len, " texel = lerp(texel, input.fog.rgb, input.fog.a);");
}
}
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, " float2 coords = (input.screenPos.xy / input.screenPos.w) * noise_scale;");
append_line(buf, &len, " texel.a *= round(random(float3(floor(coords), noise_frame)));");
}
if (cc_features.opt_alpha) {
append_line(buf, &len, " return texel;");
} else {
append_line(buf, &len, " return float4(texel, 1.0);");
}
append_line(buf, &len, "}");
}
#endif

View File

@ -1,14 +0,0 @@
#if defined(RAPI_D3D11) || defined(RAPI_D3D12)
#ifndef GFX_DIRECT3D_COMMON_H
#define GFX_DIRECT3D_COMMON_H
#include <stdint.h>
#include "gfx_cc.h"
void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_floats, const CCFeatures& cc_features, bool include_root_signature, bool three_point_filtering);
#endif
#endif

View File

@ -1,641 +0,0 @@
#ifdef WAPI_DXGI
#include <stdint.h>
#include <math.h>
#include <map>
#include <set>
#include <string>
#include <windows.h>
#include <wrl/client.h>
#include <dxgi1_3.h>
#include <versionhelpers.h>
#include <shellscalingapi.h>
#ifndef _LANGUAGE_C
#define _LANGUAGE_C
#endif
#include <PR/gbi.h>
#include "../configfile.h"
#include "../pc_main.h"
#include "gfx_window_manager_api.h"
#include "gfx_rendering_api.h"
#include "gfx_direct3d_common.h"
#include "gfx_screen_config.h"
#include "gfx_pc.h"
#define WINCLASS_NAME L"N64GAME"
#define DECLARE_GFX_DXGI_FUNCTIONS
#include "gfx_dxgi.h"
#ifdef VERSION_EU
#define FRAME_INTERVAL_US_NUMERATOR 40000
#define FRAME_INTERVAL_US_DENOMINATOR 1
#else
#define FRAME_INTERVAL_US_NUMERATOR 100000
#define FRAME_INTERVAL_US_DENOMINATOR 3
#endif
using namespace Microsoft::WRL; // For ComPtr
static struct {
HWND h_wnd;
bool showing_error;
uint32_t current_width, current_height;
std::string window_title;
HMODULE dxgi_module;
HRESULT (__stdcall *CreateDXGIFactory1)(REFIID riid, void **factory);
HRESULT (__stdcall *CreateDXGIFactory2)(UINT flags, REFIID iid, void **factory);
bool process_dpi_awareness_done;
RECT last_window_rect;
bool is_full_screen, last_maximized_state;
ComPtr<IDXGIFactory2> factory;
ComPtr<IDXGISwapChain1> swap_chain;
HANDLE waitable_object;
uint64_t qpc_init, qpc_freq;
uint64_t frame_timestamp; // in units of 1/FRAME_INTERVAL_US_DENOMINATOR microseconds
std::map<UINT, DXGI_FRAME_STATISTICS> frame_stats;
std::set<std::pair<UINT, UINT>> pending_frame_stats;
bool dropped_frame;
bool sync_interval_means_frames_to_wait;
UINT length_in_vsync_frames;
void (*run_one_game_iter)(void);
bool (*on_key_down)(int scancode);
bool (*on_key_up)(int scancode);
void (*on_all_keys_up)(void);
} dxgi;
static void load_dxgi_library(void) {
dxgi.dxgi_module = LoadLibraryW(L"dxgi.dll");
*(FARPROC *)&dxgi.CreateDXGIFactory1 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory1");
*(FARPROC *)&dxgi.CreateDXGIFactory2 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory2");
}
template <typename Fun>
static void run_as_dpi_aware(Fun f) {
// Make sure Windows 8.1 or newer doesn't upscale/downscale the rendered images.
// This is an issue on Windows 8.1 and newer where moving around the window
// between different monitors having different scaling settings will
// by default result in the DirectX image will also be scaled accordingly.
// The resulting scale factor is the curent monitor's scale factor divided by
// the initial monitor's scale factor. Setting per-monitor aware disables scaling.
// On Windows 10 1607 and later, that is solved by setting the awarenenss per window,
// which is done by using SetThreadDpiAwarenessContext before and after creating
// any window. When the message handler runs, the corresponding context also applies.
// From windef.h, missing in MinGW.
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5)
DPI_AWARENESS_CONTEXT (WINAPI *SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT dpiContext);
*(FARPROC *)&SetThreadDpiAwarenessContext = GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetThreadDpiAwarenessContext");
DPI_AWARENESS_CONTEXT old_awareness_context;
if (SetThreadDpiAwarenessContext != nullptr) {
old_awareness_context = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
} else {
// Solution for Windows 8.1 and newer, but before Windows 10 1607.
// SetProcessDpiAwareness must be called before any drawing related API is called.
if (!dxgi.process_dpi_awareness_done) {
HMODULE shcore_module = LoadLibraryW(L"SHCore.dll");
if (shcore_module != nullptr) {
HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value);
*(FARPROC *)&SetProcessDpiAwareness = GetProcAddress(shcore_module, "SetProcessDpiAwareness");
if (SetProcessDpiAwareness != nullptr) {
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
// Ignore result, will fail if already called or manifest already specifies dpi awareness.
}
FreeLibrary(shcore_module);
}
dxgi.process_dpi_awareness_done = true;
}
}
f();
// Restore the old context
if (SetThreadDpiAwarenessContext != nullptr && old_awareness_context != nullptr) {
SetThreadDpiAwarenessContext(old_awareness_context);
}
}
static void toggle_borderless_window_full_screen(bool enable) {
// Windows 7 + flip mode + waitable object can't go to exclusive fullscreen,
// so do borderless instead. If DWM is enabled, this means we get one monitor
// sync interval of latency extra. On Win 10 however (maybe Win 8 too), due to
// "fullscreen optimizations" the latency is eliminated.
if (enable == dxgi.is_full_screen) {
return;
}
if (!enable) {
RECT r = dxgi.last_window_rect;
// Set in window mode with the last saved position and size
SetWindowLongPtr(dxgi.h_wnd, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW);
if (dxgi.last_maximized_state) {
SetWindowPos(dxgi.h_wnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
ShowWindow(dxgi.h_wnd, SW_MAXIMIZE);
} else {
SetWindowPos(dxgi.h_wnd, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED);
ShowWindow(dxgi.h_wnd, SW_RESTORE);
}
ShowCursor(TRUE);
dxgi.is_full_screen = false;
} else {
// Save if window is maximized or not
WINDOWPLACEMENT window_placement;
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(dxgi.h_wnd, &window_placement);
dxgi.last_maximized_state = window_placement.showCmd == SW_SHOWMAXIMIZED;
// Save window position and size if the window is not maximized
GetWindowRect(dxgi.h_wnd, &dxgi.last_window_rect);
configWindow.x = dxgi.last_window_rect.left;
configWindow.y = dxgi.last_window_rect.top;
configWindow.w = dxgi.last_window_rect.right - dxgi.last_window_rect.left;
configWindow.h = dxgi.last_window_rect.bottom - dxgi.last_window_rect.top;
// Get in which monitor the window is
HMONITOR h_monitor = MonitorFromWindow(dxgi.h_wnd, MONITOR_DEFAULTTONEAREST);
// Get info from that monitor
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(h_monitor, &monitor_info);
RECT r = monitor_info.rcMonitor;
// Set borderless full screen to that monitor
SetWindowLongPtr(dxgi.h_wnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
SetWindowPos(dxgi.h_wnd, HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED);
ShowCursor(FALSE);
dxgi.is_full_screen = true;
}
}
static void update_screen_settings(void) {
if (configWindow.fullscreen != dxgi.is_full_screen)
toggle_borderless_window_full_screen(configWindow.fullscreen);
if (!dxgi.is_full_screen) {
const int screen_width = GetSystemMetrics(SM_CXSCREEN);
const int screen_height = GetSystemMetrics(SM_CYSCREEN);
const int xpos = (configWindow.x == WAPI_WIN_CENTERPOS) ? (screen_width - configWindow.w) * 0.5 : configWindow.x;
const int ypos = (configWindow.y == WAPI_WIN_CENTERPOS) ? (screen_height - configWindow.h) * 0.5 : configWindow.y;
RECT wr = { xpos, ypos, xpos + (int)configWindow.w, ypos + (int)configWindow.h };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
SetWindowPos(dxgi.h_wnd, NULL, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top, SWP_NOACTIVATE | SWP_NOZORDER);
}
}
static void gfx_dxgi_on_resize(void) {
if (dxgi.swap_chain.Get() != nullptr) {
gfx_get_current_rendering_api()->on_resize();
DXGI_SWAP_CHAIN_DESC1 desc1;
ThrowIfFailed(dxgi.swap_chain->GetDesc1(&desc1));
dxgi.current_width = desc1.Width;
dxgi.current_height = desc1.Height;
if (!dxgi.is_full_screen) {
configWindow.w = dxgi.current_width;
configWindow.h = dxgi.current_height;
}
}
}
static void onkeydown(WPARAM w_param, LPARAM l_param) {
int key = ((l_param >> 16) & 0x1ff);
if (dxgi.on_key_down != nullptr) {
dxgi.on_key_down(key);
}
}
static void onkeyup(WPARAM w_param, LPARAM l_param) {
int key = ((l_param >> 16) & 0x1ff);
if (dxgi.on_key_up != nullptr) {
dxgi.on_key_up(key);
}
}
static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_param, LPARAM l_param) {
switch (message) {
case WM_SIZE:
gfx_dxgi_on_resize();
break;
case WM_DESTROY:
game_exit();
break;
case WM_PAINT:
if (dxgi.showing_error) {
return DefWindowProcW(h_wnd, message, w_param, l_param);
} else {
if (dxgi.run_one_game_iter != nullptr) {
dxgi.run_one_game_iter();
}
}
break;
case WM_ACTIVATEAPP:
if (dxgi.on_all_keys_up != nullptr) {
dxgi.on_all_keys_up();
}
break;
case WM_KEYDOWN:
onkeydown(w_param, l_param);
break;
case WM_KEYUP:
onkeyup(w_param, l_param);
break;
case WM_SYSKEYDOWN:
if ((w_param == VK_RETURN) && ((l_param & 1 << 30) == 0)) {
toggle_borderless_window_full_screen(!dxgi.is_full_screen);
break;
} else {
return DefWindowProcW(h_wnd, message, w_param, l_param);
}
default:
return DefWindowProcW(h_wnd, message, w_param, l_param);
}
if (configWindow.reset) {
dxgi.last_maximized_state = false;
configWindow.reset = false;
configWindow.x = WAPI_WIN_CENTERPOS;
configWindow.y = WAPI_WIN_CENTERPOS;
configWindow.w = DESIRED_SCREEN_WIDTH;
configWindow.h = DESIRED_SCREEN_HEIGHT;
configWindow.fullscreen = false;
configWindow.settings_changed = true;
}
if (configWindow.settings_changed) {
configWindow.settings_changed = false;
update_screen_settings();
}
return 0;
}
static void gfx_dxgi_init(const char *window_title) {
LARGE_INTEGER qpc_init, qpc_freq;
QueryPerformanceCounter(&qpc_init);
QueryPerformanceFrequency(&qpc_freq);
dxgi.qpc_init = qpc_init.QuadPart;
dxgi.qpc_freq = qpc_freq.QuadPart;
// Prepare window title
wchar_t w_title[512];
int len = strlen(window_title);
mbstowcs(w_title, window_title, len + 1);
dxgi.window_title = window_title;
// Create window
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = gfx_dxgi_wnd_proc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = nullptr;
wcex.hIcon = nullptr;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = WINCLASS_NAME;
wcex.hIconSm = nullptr;
ATOM winclass = RegisterClassExW(&wcex);
run_as_dpi_aware([&] () {
// We need to be dpi aware when calculating the size
RECT wr = {0, 0, DESIRED_SCREEN_WIDTH, DESIRED_SCREEN_HEIGHT};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
dxgi.h_wnd = CreateWindowW(WINCLASS_NAME, w_title, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, wr.right - wr.left, wr.bottom - wr.top, nullptr, nullptr, nullptr, nullptr);
});
load_dxgi_library();
ShowWindow(dxgi.h_wnd, SW_SHOW);
UpdateWindow(dxgi.h_wnd);
update_screen_settings();
}
static void gfx_dxgi_set_keyboard_callbacks(bool (*on_key_down)(int scancode), bool (*on_key_up)(int scancode), void (*on_all_keys_up)(void)) {
dxgi.on_key_down = on_key_down;
dxgi.on_key_up = on_key_up;
dxgi.on_all_keys_up = on_all_keys_up;
}
static void gfx_dxgi_main_loop(void (*run_one_game_iter)(void)) {
dxgi.run_one_game_iter = run_one_game_iter;
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
static void gfx_dxgi_get_dimensions(uint32_t *width, uint32_t *height) {
*width = dxgi.current_width;
*height = dxgi.current_height;
}
static void gfx_dxgi_handle_events(void) {
/*MSG msg;
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}*/
}
static uint64_t qpc_to_us(uint64_t qpc) {
return qpc / dxgi.qpc_freq * 1000000 + qpc % dxgi.qpc_freq * 1000000 / dxgi.qpc_freq;
}
static bool gfx_dxgi_start_frame(void) {
DXGI_FRAME_STATISTICS stats;
if (dxgi.swap_chain->GetFrameStatistics(&stats) == S_OK && (stats.SyncRefreshCount != 0 || stats.SyncQPCTime.QuadPart != 0ULL)) {
{
LARGE_INTEGER t0;
QueryPerformanceCounter(&t0);
//printf("Get frame stats: %llu\n", (unsigned long long)(t0.QuadPart - dxgi.qpc_init));
}
//printf("stats: %u %u %u %u %u %.6f\n", dxgi.pending_frame_stats.rbegin()->first, dxgi.pending_frame_stats.rbegin()->second, stats.PresentCount, stats.PresentRefreshCount, stats.SyncRefreshCount, (double)(stats.SyncQPCTime.QuadPart - dxgi.qpc_init) / dxgi.qpc_freq);
if (dxgi.frame_stats.empty() || dxgi.frame_stats.rbegin()->second.PresentCount != stats.PresentCount) {
dxgi.frame_stats.insert(std::make_pair(stats.PresentCount, stats));
}
if (dxgi.frame_stats.size() > 3) {
dxgi.frame_stats.erase(dxgi.frame_stats.begin());
}
}
if (!dxgi.frame_stats.empty()) {
while (!dxgi.pending_frame_stats.empty() && dxgi.pending_frame_stats.begin()->first < dxgi.frame_stats.rbegin()->first) {
dxgi.pending_frame_stats.erase(dxgi.pending_frame_stats.begin());
}
}
while (dxgi.pending_frame_stats.size() > 15) {
// Just make sure the list doesn't grow too large if GetFrameStatistics fails.
dxgi.pending_frame_stats.erase(dxgi.pending_frame_stats.begin());
}
dxgi.frame_timestamp += FRAME_INTERVAL_US_NUMERATOR;
if (dxgi.frame_stats.size() >= 2) {
DXGI_FRAME_STATISTICS *first = &dxgi.frame_stats.begin()->second;
DXGI_FRAME_STATISTICS *last = &dxgi.frame_stats.rbegin()->second;
uint64_t sync_qpc_diff = last->SyncQPCTime.QuadPart - first->SyncQPCTime.QuadPart;
UINT sync_vsync_diff = last->SyncRefreshCount - first->SyncRefreshCount;
UINT present_vsync_diff = last->PresentRefreshCount - first->PresentRefreshCount;
UINT present_diff = last->PresentCount - first->PresentCount;
if (sync_vsync_diff == 0) {
sync_vsync_diff = 1;
}
double estimated_vsync_interval = (double)sync_qpc_diff / (double)sync_vsync_diff;
uint64_t estimated_vsync_interval_us = qpc_to_us(estimated_vsync_interval);
//printf("Estimated vsync_interval: %d\n", (int)estimated_vsync_interval_us);
if (estimated_vsync_interval_us < 2 || estimated_vsync_interval_us > 1000000) {
// Unreasonable, maybe a monitor change
estimated_vsync_interval_us = 16666;
estimated_vsync_interval = estimated_vsync_interval_us * dxgi.qpc_freq / 1000000;
}
UINT queued_vsyncs = 0;
bool is_first = true;
for (const std::pair<UINT, UINT>& p : dxgi.pending_frame_stats) {
if (is_first && dxgi.sync_interval_means_frames_to_wait) {
is_first = false;
continue;
}
queued_vsyncs += p.second;
}
uint64_t last_frame_present_end_qpc = (last->SyncQPCTime.QuadPart - dxgi.qpc_init) + estimated_vsync_interval * queued_vsyncs;
uint64_t last_end_us = qpc_to_us(last_frame_present_end_qpc);
double vsyncs_to_wait = (double)(int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR - last_end_us) / estimated_vsync_interval_us;
//printf("ts: %llu, last_end_us: %llu, Init v: %f\n", dxgi.frame_timestamp / 3, last_end_us, vsyncs_to_wait);
if (vsyncs_to_wait <= 0) {
// Too late
if ((int64_t)(dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR - last_end_us) < -66666) {
// The application must have been paused or similar
vsyncs_to_wait = round(((double)FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR) / estimated_vsync_interval_us);
if (vsyncs_to_wait < 1) {
vsyncs_to_wait = 1;
}
dxgi.frame_timestamp = FRAME_INTERVAL_US_DENOMINATOR * (last_end_us + vsyncs_to_wait * estimated_vsync_interval_us);
} else {
// Drop frame
//printf("Dropping frame\n");
dxgi.dropped_frame = true;
return false;
}
}
if (floor(vsyncs_to_wait) != vsyncs_to_wait) {
uint64_t left = last_end_us + floor(vsyncs_to_wait) * estimated_vsync_interval_us;
uint64_t right = last_end_us + ceil(vsyncs_to_wait) * estimated_vsync_interval_us;
uint64_t adjusted_desired_time = dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR + (last_end_us + (FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR) > dxgi.frame_timestamp / FRAME_INTERVAL_US_DENOMINATOR ? 2000 : -2000);
int64_t diff_left = adjusted_desired_time - left;
int64_t diff_right = right - adjusted_desired_time;
if (diff_left < 0) {
diff_left = -diff_left;
}
if (diff_right < 0) {
diff_right = -diff_right;
}
if (diff_left < diff_right) {
vsyncs_to_wait = floor(vsyncs_to_wait);
} else {
vsyncs_to_wait = ceil(vsyncs_to_wait);
}
if (vsyncs_to_wait == 0) {
//printf("vsyncs_to_wait became 0 so dropping frame\n");
dxgi.dropped_frame = true;
return false;
}
}
//printf("v: %d\n", (int)vsyncs_to_wait);
if (vsyncs_to_wait > 4) {
// Invalid, so change to 4
vsyncs_to_wait = 4;
}
dxgi.length_in_vsync_frames = vsyncs_to_wait;
} else {
dxgi.length_in_vsync_frames = 2;
}
return true;
}
static void gfx_dxgi_swap_buffers_begin(void) {
//dxgi.length_in_vsync_frames = 1;
ThrowIfFailed(dxgi.swap_chain->Present(dxgi.length_in_vsync_frames, 0));
UINT this_present_id;
if (dxgi.swap_chain->GetLastPresentCount(&this_present_id) == S_OK) {
dxgi.pending_frame_stats.insert(std::make_pair(this_present_id, dxgi.length_in_vsync_frames));
}
dxgi.dropped_frame = false;
}
static void gfx_dxgi_swap_buffers_end(void) {
LARGE_INTEGER t0, t1, t2;
QueryPerformanceCounter(&t0);
QueryPerformanceCounter(&t1);
if (!dxgi.dropped_frame) {
if (dxgi.waitable_object != nullptr) {
WaitForSingleObject(dxgi.waitable_object, INFINITE);
}
// else TODO: maybe sleep until some estimated time the frame will be shown to reduce lag
}
DXGI_FRAME_STATISTICS stats;
dxgi.swap_chain->GetFrameStatistics(&stats);
QueryPerformanceCounter(&t2);
dxgi.sync_interval_means_frames_to_wait = dxgi.pending_frame_stats.rbegin()->first == stats.PresentCount;
//printf("done %llu gpu:%d wait:%d freed:%llu frame:%u %u monitor:%u t:%llu\n", (unsigned long long)(t0.QuadPart - dxgi.qpc_init), (int)(t1.QuadPart - t0.QuadPart), (int)(t2.QuadPart - t0.QuadPart), (unsigned long long)(t2.QuadPart - dxgi.qpc_init), dxgi.pending_frame_stats.rbegin()->first, stats.PresentCount, stats.SyncRefreshCount, (unsigned long long)(stats.SyncQPCTime.QuadPart - dxgi.qpc_init));
}
static double gfx_dxgi_get_time(void) {
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
return (double)(t.QuadPart - dxgi.qpc_init) / dxgi.qpc_freq;
}
void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*create_device_fn)(IDXGIAdapter1 *adapter, bool test_only)) {
if (dxgi.CreateDXGIFactory2 != nullptr) {
ThrowIfFailed(dxgi.CreateDXGIFactory2(debug ? DXGI_CREATE_FACTORY_DEBUG : 0, __uuidof(IDXGIFactory2), &dxgi.factory));
} else {
ThrowIfFailed(dxgi.CreateDXGIFactory1(__uuidof(IDXGIFactory2), &dxgi.factory));
}
ComPtr<IDXGIAdapter1> adapter;
for (UINT i = 0; dxgi.factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
if (desc.Flags & 2/*DXGI_ADAPTER_FLAG_SOFTWARE*/) { // declaration missing in mingw headers
continue;
}
if (create_device_fn(adapter.Get(), true)) {
break;
}
}
create_device_fn(adapter.Get(), false);
wchar_t w_title[512];
int len = dxgi.window_title.length();
mbstowcs(w_title, dxgi.window_title.c_str(), len + 1);
SetWindowTextW(dxgi.h_wnd, w_title);
}
ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device) {
bool win8 = IsWindows8OrGreater(); // DXGI_SCALING_NONE is only supported on Win8 and beyond
bool dxgi_13 = dxgi.CreateDXGIFactory2 != nullptr; // DXGI 1.3 introduced waitable object
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
swap_chain_desc.BufferCount = 2;
swap_chain_desc.Width = 0;
swap_chain_desc.Height = 0;
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.Scaling = win8 ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // Apparently this was backported to Win 7 Platform Update
swap_chain_desc.Flags = dxgi_13 ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0;
swap_chain_desc.SampleDesc.Count = 1;
run_as_dpi_aware([&] () {
// When setting size for the buffers, the values that DXGI puts into the desc (that can later be retrieved by GetDesc1)
// have been divided by the current scaling factor. By making this call dpi aware, no division will be performed.
// The same goes for IDXGISwapChain::ResizeBuffers(), however that function is currently only called from the message handler.
ThrowIfFailed(dxgi.factory->CreateSwapChainForHwnd(device, dxgi.h_wnd, &swap_chain_desc, nullptr, nullptr, &dxgi.swap_chain));
});
ThrowIfFailed(dxgi.factory->MakeWindowAssociation(dxgi.h_wnd, DXGI_MWA_NO_ALT_ENTER));
ComPtr<IDXGISwapChain2> swap_chain2;
if (dxgi.swap_chain->QueryInterface(__uuidof(IDXGISwapChain2), &swap_chain2) == S_OK) {
ThrowIfFailed(swap_chain2->SetMaximumFrameLatency(1));
dxgi.waitable_object = swap_chain2->GetFrameLatencyWaitableObject();
WaitForSingleObject(dxgi.waitable_object, INFINITE);
} else {
ComPtr<IDXGIDevice1> device1;
ThrowIfFailed(device->QueryInterface(IID_PPV_ARGS(&device1)));
ThrowIfFailed(device1->SetMaximumFrameLatency(1));
}
ThrowIfFailed(dxgi.swap_chain->GetDesc1(&swap_chain_desc));
dxgi.current_width = swap_chain_desc.Width;
dxgi.current_height = swap_chain_desc.Height;
return dxgi.swap_chain;
}
HWND gfx_dxgi_get_h_wnd(void) {
return dxgi.h_wnd;
}
void gfx_dxgi_shutdown(void) {
}
void ThrowIfFailed(HRESULT res) {
if (FAILED(res)) {
fprintf(stderr, "Error: 0x%08X\n", res);
throw res;
}
}
void ThrowIfFailed(HRESULT res, HWND h_wnd, const char *message) {
if (FAILED(res)) {
char full_message[256];
sprintf(full_message, "%s\n\nHRESULT: 0x%08X", message, res);
dxgi.showing_error = true;
MessageBox(h_wnd, full_message, "Error", MB_OK | MB_ICONERROR);
throw res;
}
}
struct GfxWindowManagerAPI gfx_dxgi = {
gfx_dxgi_init,
gfx_dxgi_set_keyboard_callbacks,
gfx_dxgi_main_loop,
gfx_dxgi_get_dimensions,
gfx_dxgi_handle_events,
gfx_dxgi_start_frame,
gfx_dxgi_swap_buffers_begin,
gfx_dxgi_swap_buffers_end,
gfx_dxgi_get_time,
gfx_dxgi_shutdown,
};
#endif

View File

@ -1,16 +0,0 @@
#ifndef GFX_DXGI_H
#define GFX_DXGI_H
#include "gfx_rendering_api.h"
#ifdef DECLARE_GFX_DXGI_FUNCTIONS
void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*create_device_fn)(IDXGIAdapter1 *adapter, bool test_only));
Microsoft::WRL::ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device);
HWND gfx_dxgi_get_h_wnd(void);
void ThrowIfFailed(HRESULT res);
void ThrowIfFailed(HRESULT res, HWND h_wnd, const char *message);
#endif
extern struct GfxWindowManagerAPI gfx_dxgi;
#endif

View File

@ -14,10 +14,6 @@
#include "gfx/gfx_pc.h"
#include "gfx/gfx_opengl.h"
#include "gfx/gfx_direct3d11.h"
#include "gfx/gfx_direct3d12.h"
#include "gfx/gfx_dxgi.h"
#include "gfx/gfx_sdl.h"
#include "audio/audio_api.h"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB