mirror of https://github.com/sm64pc/sm64pc.git
Removed dx render api and added rumble logo
This commit is contained in:
parent
18d69ff933
commit
4ed2e05870
|
@ -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(),
|
||||
};
|
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 |
Loading…
Reference in New Issue