Graphics backend enhancements etc. (#163)

This commit is contained in:
Emill 2022-04-18 11:37:47 +02:00 committed by GitHub
parent fe6dbd2a5b
commit ceef4a9453
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 872 additions and 588 deletions

View File

@ -52,6 +52,11 @@ struct SoHConfigType {
bool moon_jump_on_l = false; bool moon_jump_on_l = false;
bool super_tunic = false; bool super_tunic = false;
} cheats; } cheats;
// Graphics
struct {
bool show = false;
} graphics;
}; };
enum SeqPlayers { enum SeqPlayers {

View File

@ -37,9 +37,8 @@ namespace {
struct PerFrameCB { struct PerFrameCB {
uint32_t noise_frame; uint32_t noise_frame;
float noise_scale_x; float noise_scale;
float noise_scale_y; uint32_t padding[2]; // constant buffers must be multiples of 16 bytes in size
uint32_t padding;
}; };
struct PerDrawCB { struct PerDrawCB {
@ -51,12 +50,12 @@ struct PerDrawCB {
} textures[2]; } textures[2];
}; };
struct CoordCB { struct Coord {
float x, y; int x, y;
float padding[2]; // structure size must be multiple of 16
}; };
struct TextureData { struct TextureData {
ComPtr<ID3D11Texture2D> texture;
ComPtr<ID3D11ShaderResourceView> resource_view; ComPtr<ID3D11ShaderResourceView> resource_view;
ComPtr<ID3D11SamplerState> sampler_state; ComPtr<ID3D11SamplerState> sampler_state;
uint32_t width; uint32_t width;
@ -64,10 +63,13 @@ struct TextureData {
bool linear_filtering; bool linear_filtering;
}; };
struct FramebufferData { struct Framebuffer {
ComPtr<ID3D11RenderTargetView> render_target_view; ComPtr<ID3D11RenderTargetView> render_target_view;
ComPtr<ID3D11DepthStencilView> depth_stencil_view; ComPtr<ID3D11DepthStencilView> depth_stencil_view;
ComPtr<ID3D11ShaderResourceView> depth_stencil_srv;
uint32_t texture_id; uint32_t texture_id;
bool has_depth_buffer;
uint32_t msaa_level;
}; };
struct ShaderProgramD3D11 { struct ShaderProgramD3D11 {
@ -91,34 +93,30 @@ static struct {
pD3DCompile D3DCompile; pD3DCompile D3DCompile;
D3D_FEATURE_LEVEL feature_level; D3D_FEATURE_LEVEL feature_level;
uint32_t msaa_num_quality_levels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT];
ComPtr<ID3D11Device> device; ComPtr<ID3D11Device> device;
ComPtr<IDXGISwapChain1> swap_chain; ComPtr<IDXGISwapChain1> swap_chain;
ComPtr<ID3D11DeviceContext> context; ComPtr<ID3D11DeviceContext> context;
ComPtr<ID3D11RenderTargetView> backbuffer_view;
ComPtr<ID3D11DepthStencilView> depth_stencil_view;
ComPtr<ID3D11ShaderResourceView> depth_stencil_srv;
ComPtr<ID3D11RasterizerState> rasterizer_state; ComPtr<ID3D11RasterizerState> rasterizer_state;
ComPtr<ID3D11DepthStencilState> depth_stencil_state; ComPtr<ID3D11DepthStencilState> depth_stencil_state;
ComPtr<ID3D11Buffer> vertex_buffer; ComPtr<ID3D11Buffer> vertex_buffer;
ComPtr<ID3D11Buffer> per_frame_cb; ComPtr<ID3D11Buffer> per_frame_cb;
ComPtr<ID3D11Buffer> per_draw_cb; ComPtr<ID3D11Buffer> per_draw_cb;
ComPtr<ID3D11Texture2D> depth_stencil_texture;
ComPtr<ID3D11Texture2D> depth_stencil_copy_texture;
ComPtr<ID3D11Buffer> coord_buffer; ComPtr<ID3D11Buffer> coord_buffer;
ComPtr<ID3D11ShaderResourceView> coord_buffer_srv;
ComPtr<ID3D11Buffer> depth_value_output_buffer; ComPtr<ID3D11Buffer> depth_value_output_buffer;
ComPtr<ID3D11Buffer> depth_value_output_buffer_copy; ComPtr<ID3D11Buffer> depth_value_output_buffer_copy;
ComPtr<ID3D11UnorderedAccessView> depth_value_output_uav; ComPtr<ID3D11UnorderedAccessView> depth_value_output_uav;
ComPtr<ID3D11SamplerState> depth_value_sampler;
ComPtr<ID3D11ComputeShader> compute_shader; ComPtr<ID3D11ComputeShader> compute_shader;
bool copied_depth_buffer; ComPtr<ID3D11ComputeShader> compute_shader_msaa;
ComPtr<ID3DBlob> compute_shader_msaa_blob;
size_t coord_buffer_size;
#if DEBUG_D3D #if DEBUG_D3D
ComPtr<ID3D11Debug> debug; ComPtr<ID3D11Debug> debug;
#endif #endif
DXGI_SAMPLE_DESC sample_description;
PerFrameCB per_frame_cb_data; PerFrameCB per_frame_cb_data;
PerDrawCB per_draw_cb_data; PerDrawCB per_draw_cb_data;
@ -128,14 +126,15 @@ static struct {
int current_tile; int current_tile;
uint32_t current_texture_ids[2]; uint32_t current_texture_ids[2];
std::vector<FramebufferData> framebuffers; std::vector<Framebuffer> framebuffers;
// Current state // Current state
struct ShaderProgramD3D11 *shader_program; struct ShaderProgramD3D11 *shader_program;
uint32_t current_width, current_height; //uint32_t current_width, current_height;
uint32_t render_target_height; uint32_t render_target_height;
int current_framebuffer;
int8_t depth_test; int8_t depth_test;
int8_t depth_mask; int8_t depth_mask;
@ -156,7 +155,9 @@ static struct {
static LARGE_INTEGER last_time, accumulated_time, frequency; static LARGE_INTEGER last_time, accumulated_time, frequency;
void create_depth_stencil_objects(uint32_t width, uint32_t height, ID3D11Texture2D **texture, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) { int gfx_d3d11_create_framebuffer(void);
void create_depth_stencil_objects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) {
D3D11_TEXTURE2D_DESC texture_desc; D3D11_TEXTURE2D_DESC texture_desc;
texture_desc.Width = width; texture_desc.Width = width;
texture_desc.Height = height; texture_desc.Height = height;
@ -164,93 +165,42 @@ void create_depth_stencil_objects(uint32_t width, uint32_t height, ID3D11Texture
texture_desc.ArraySize = 1; texture_desc.ArraySize = 1;
texture_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ? texture_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R24G8_TYPELESS; DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R24G8_TYPELESS;
texture_desc.SampleDesc.Count = 1; texture_desc.SampleDesc.Count = msaa_count;
texture_desc.SampleDesc.Quality = 0; texture_desc.SampleDesc.Quality = 0;
texture_desc.Usage = D3D11_USAGE_DEFAULT; texture_desc.Usage = D3D11_USAGE_DEFAULT;
texture_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | (srv != nullptr ? D3D11_BIND_SHADER_RESOURCE : 0); texture_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | (srv != nullptr ? D3D11_BIND_SHADER_RESOURCE : 0);
texture_desc.CPUAccessFlags = 0; texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0; texture_desc.MiscFlags = 0;
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, texture)); ComPtr<ID3D11Texture2D> texture;
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, texture.GetAddressOf()));
D3D11_DEPTH_STENCIL_VIEW_DESC view_desc; D3D11_DEPTH_STENCIL_VIEW_DESC view_desc;
view_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ? view_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_D24_UNORM_S8_UINT; DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_D24_UNORM_S8_UINT;
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
view_desc.Flags = 0; view_desc.Flags = 0;
view_desc.Texture2D.MipSlice = 0; if (msaa_count > 1) {
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
view_desc.Texture2DMS.UnusedField_NothingToDefine = 0;
} else {
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
view_desc.Texture2D.MipSlice = 0;
}
ThrowIfFailed(d3d.device->CreateDepthStencilView(*texture, &view_desc, view)); ThrowIfFailed(d3d.device->CreateDepthStencilView(texture.Get(), &view_desc, view));
if (srv != nullptr) { if (srv != nullptr) {
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
srv_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ? srv_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
DXGI_FORMAT_R32_FLOAT : DXGI_FORMAT_R24_UNORM_X8_TYPELESS; DXGI_FORMAT_R32_FLOAT : DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srv_desc.ViewDimension = msaa_count > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MostDetailedMip = 0; srv_desc.Texture2D.MostDetailedMip = 0;
srv_desc.Texture2D.MipLevels = -1; srv_desc.Texture2D.MipLevels = -1;
ThrowIfFailed(d3d.device->CreateShaderResourceView(*texture, &srv_desc, srv)); ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), &srv_desc, srv));
} }
} }
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_texture.Reset();
d3d.depth_stencil_view.Reset();
d3d.depth_stencil_srv.Reset();
d3d.depth_stencil_copy_texture.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
create_depth_stencil_objects(desc1.Width, desc1.Height, d3d.depth_stencil_texture.GetAddressOf(), d3d.depth_stencil_view.GetAddressOf(), d3d.depth_stencil_srv.GetAddressOf());
// Create texture that can be used to retrieve depth value
D3D11_TEXTURE2D_DESC depth_texture = {};
depth_texture.Width = desc1.Width;
depth_texture.Height = desc1.Height;
depth_texture.MipLevels = 1;
depth_texture.ArraySize = 1;
depth_texture.Format = DXGI_FORMAT_D32_FLOAT;
depth_texture.SampleDesc.Count = 1;
depth_texture.SampleDesc.Quality = 0;
depth_texture.Usage = D3D11_USAGE_STAGING;
depth_texture.BindFlags = 0;
depth_texture.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
depth_texture.MiscFlags = 0;
ThrowIfFailed(d3d.device->CreateTexture2D(&depth_texture, nullptr, d3d.depth_stencil_copy_texture.GetAddressOf()));
// Save resolution
d3d.current_width = desc1.Width;
d3d.current_height = desc1.Height;
}
static void gfx_d3d11_init(void) { static void gfx_d3d11_init(void) {
// Load d3d11.dll // Load d3d11.dll
d3d.d3d11_module = LoadLibraryW(L"d3d11.dll"); d3d.d3d11_module = LoadLibraryW(L"d3d11.dll");
@ -300,11 +250,6 @@ static void gfx_d3d11_init(void) {
} }
}); });
// 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 // Create the swap chain
d3d.swap_chain = gfx_dxgi_create_swap_chain(d3d.device.Get()); d3d.swap_chain = gfx_dxgi_create_swap_chain(d3d.device.Get());
@ -315,9 +260,19 @@ static void gfx_d3d11_init(void) {
gfx_dxgi_get_h_wnd(), "Failed to get ID3D11Debug device."); gfx_dxgi_get_h_wnd(), "Failed to get ID3D11Debug device.");
#endif #endif
// Create views // Create the default framebuffer which represents the window
Framebuffer& fb = d3d.framebuffers[gfx_d3d11_create_framebuffer()];
create_render_target_views(false); // Check the size of the window
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
ThrowIfFailed(d3d.swap_chain->GetDesc1(&swap_chain_desc));
d3d.textures[fb.texture_id].width = swap_chain_desc.Width;
d3d.textures[fb.texture_id].height = swap_chain_desc.Height;
fb.msaa_level = 1;
for (uint32_t sample_count = 1; sample_count <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sample_count++) {
ThrowIfFailed(d3d.device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, sample_count, &d3d.msaa_num_quality_levels[sample_count - 1]));
}
// Create main vertex buffer // Create main vertex buffer
@ -364,61 +319,30 @@ static void gfx_d3d11_init(void) {
// Create compute shader that can be used to retrieve depth buffer values // Create compute shader that can be used to retrieve depth buffer values
D3D11_BUFFER_DESC coord_cb_desc;
coord_cb_desc.Usage = D3D11_USAGE_DYNAMIC;
coord_cb_desc.ByteWidth = sizeof(CoordCB);
coord_cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
coord_cb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
coord_cb_desc.MiscFlags = 0;
coord_cb_desc.StructureByteStride = 0;
ThrowIfFailed(d3d.device->CreateBuffer(&coord_cb_desc, nullptr, d3d.coord_buffer.GetAddressOf()));
D3D11_SAMPLER_DESC sampler_desc = {};
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
sampler_desc.MinLOD = 0;
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
ThrowIfFailed(d3d.device->CreateSamplerState(&sampler_desc, d3d.depth_value_sampler.GetAddressOf()));
D3D11_BUFFER_DESC output_buffer_desc;
output_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
output_buffer_desc.ByteWidth = sizeof(float);
output_buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
output_buffer_desc.CPUAccessFlags = 0;
output_buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
output_buffer_desc.StructureByteStride = sizeof(float);
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer.GetAddressOf()));
D3D11_UNORDERED_ACCESS_VIEW_DESC output_buffer_uav_desc;
output_buffer_uav_desc.Format = DXGI_FORMAT_UNKNOWN;
output_buffer_uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
output_buffer_uav_desc.Buffer.FirstElement = 0;
output_buffer_uav_desc.Buffer.NumElements = 1;
output_buffer_uav_desc.Buffer.Flags = 0;
ThrowIfFailed(d3d.device->CreateUnorderedAccessView(d3d.depth_value_output_buffer.Get(), &output_buffer_uav_desc, d3d.depth_value_output_uav.GetAddressOf()));
output_buffer_desc.Usage = D3D11_USAGE_STAGING;
output_buffer_desc.BindFlags = 0;
output_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer_copy.GetAddressOf()));
const char* shader_source = R"( const char* shader_source = R"(
sampler my_sampler : register(s0); sampler my_sampler : register(s0);
Texture2D<float> tex : register(t0); Texture2D<float> tex : register(t0);
cbuffer coordCB : register(b0) { StructuredBuffer<int2> coord : register(t1);
float2 coord;
}
RWStructuredBuffer<float> output : register(u0); RWStructuredBuffer<float> output : register(u0);
[numthreads(1, 1, 1)] [numthreads(1, 1, 1)]
void CSMain(uint3 DTid : SV_DispatchThreadID) { void CSMain(uint3 DTid : SV_DispatchThreadID) {
output[0] = tex.SampleLevel(my_sampler, coord, 0); output[DTid.x] = tex.Load(int3(coord[DTid.x], 0));
} }
)"; )";
const char* shader_source_msaa = R"(
sampler my_sampler : register(s0);
Texture2DMS<float, 2> tex : register(t0);
StructuredBuffer<int2> coord : register(t1);
RWStructuredBuffer<float> output : register(u0);
[numthreads(1, 1, 1)]
void CSMain(uint3 DTid : SV_DispatchThreadID) {
output[DTid.x] = tex.Load(coord[DTid.x], 0);
}
)";
#if DEBUG_D3D #if DEBUG_D3D
UINT compile_flags = D3DCOMPILE_DEBUG; UINT compile_flags = D3DCOMPILE_DEBUG;
#else #else
@ -426,7 +350,9 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
#endif #endif
ComPtr<ID3DBlob> cs, error_blob; ComPtr<ID3DBlob> cs, error_blob;
HRESULT hr = d3d.D3DCompile(shader_source, strlen(shader_source), nullptr, nullptr, nullptr, "CSMain", "cs_4_0", compile_flags, 0, cs.GetAddressOf(), error_blob.GetAddressOf()); HRESULT hr;
hr = d3d.D3DCompile(shader_source, strlen(shader_source), nullptr, nullptr, nullptr, "CSMain", "cs_4_0", compile_flags, 0, cs.GetAddressOf(), error_blob.GetAddressOf());
if (FAILED(hr)) { if (FAILED(hr)) {
char* err = (char*)error_blob->GetBufferPointer(); char* err = (char*)error_blob->GetBufferPointer();
@ -436,6 +362,14 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
ThrowIfFailed(d3d.device->CreateComputeShader(cs->GetBufferPointer(), cs->GetBufferSize(), nullptr, d3d.compute_shader.GetAddressOf())); ThrowIfFailed(d3d.device->CreateComputeShader(cs->GetBufferPointer(), cs->GetBufferSize(), nullptr, d3d.compute_shader.GetAddressOf()));
hr = d3d.D3DCompile(shader_source_msaa, strlen(shader_source_msaa), nullptr, nullptr, nullptr, "CSMain", "cs_4_1", compile_flags, 0, d3d.compute_shader_msaa_blob.GetAddressOf(), error_blob.ReleaseAndGetAddressOf());
if (FAILED(hr)) {
char* err = (char*)error_blob->GetBufferPointer();
MessageBoxA(gfx_dxgi_get_h_wnd(), err, "Error", MB_OK | MB_ICONERROR);
throw hr;
}
// Create ImGui // Create ImGui
SohImGui::WindowImpl window_impl; SohImGui::WindowImpl window_impl;
@ -445,8 +379,8 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
} }
static bool gfx_d3d11_z_is_from_0_to_1(void) { static struct GfxClipParameters gfx_d3d11_get_clip_parameters(void) {
return true; return { true, false };
} }
static void gfx_d3d11_unload_shader(struct ShaderProgram *old_prg) { static void gfx_d3d11_unload_shader(struct ShaderProgram *old_prg) {
@ -531,8 +465,8 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_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].BlendOp = D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; // We initially clear alpha to 1.0f and want to keep it at 1.0f
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
} else { } else {
@ -592,6 +526,10 @@ static D3D11_TEXTURE_ADDRESS_MODE gfx_cm_to_d3d11(uint32_t val) {
static void gfx_d3d11_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) { static void gfx_d3d11_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) {
// Create texture // Create texture
TextureData *texture_data = &d3d.textures[d3d.current_texture_ids[d3d.current_tile]];
texture_data->width = width;
texture_data->height = height;
D3D11_TEXTURE2D_DESC texture_desc; D3D11_TEXTURE2D_DESC texture_desc;
ZeroMemory(&texture_desc, sizeof(D3D11_TEXTURE2D_DESC)); ZeroMemory(&texture_desc, sizeof(D3D11_TEXTURE2D_DESC));
@ -612,21 +550,11 @@ static void gfx_d3d11_upload_texture(const uint8_t *rgba32_buf, uint32_t width,
resource_data.SysMemPitch = width * 4; resource_data.SysMemPitch = width * 4;
resource_data.SysMemSlicePitch = resource_data.SysMemPitch * height; resource_data.SysMemSlicePitch = resource_data.SysMemPitch * height;
ComPtr<ID3D11Texture2D> texture; ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, &resource_data, texture_data->texture.ReleaseAndGetAddressOf()));
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, &resource_data, texture.GetAddressOf()));
TextureData *texture_data = &d3d.textures[d3d.current_texture_ids[d3d.current_tile]];
texture_data->width = width;
texture_data->height = height;
// Create shader resource view from texture // Create shader resource view from texture
if (texture_data->resource_view.Get() != nullptr) { ThrowIfFailed(d3d.device->CreateShaderResourceView(texture_data->texture.Get(), nullptr, texture_data->resource_view.ReleaseAndGetAddressOf()));
// Free the previous texture in this slot
texture_data->resource_view.Reset();
}
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), nullptr, texture_data->resource_view.GetAddressOf()));
} }
static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
@ -803,20 +731,10 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t
} }
static void gfx_d3d11_on_resize(void) { static void gfx_d3d11_on_resize(void) {
create_render_target_views(true); //create_render_target_views(true);
} }
static void gfx_d3d11_start_frame(void) { static void gfx_d3d11_start_frame(void) {
// 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 // Set per-frame constant buffer
d3d.per_frame_cb_data.noise_frame++; d3d.per_frame_cb_data.noise_frame++;
@ -824,22 +742,9 @@ static void gfx_d3d11_start_frame(void) {
// No high values, as noise starts to look ugly // No high values, as noise starts to look ugly
d3d.per_frame_cb_data.noise_frame = 0; d3d.per_frame_cb_data.noise_frame = 0;
} }
float aspect_ratio = (float) d3d.current_width / (float) d3d.current_height;
d3d.render_target_height = d3d.current_height;
d3d.per_frame_cb_data.noise_scale_x = 120 * aspect_ratio; // 120 = N64 height resolution (240) / 2
d3d.per_frame_cb_data.noise_scale_y = 120;
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);
d3d.copied_depth_buffer = false;
} }
static void gfx_d3d11_end_frame(void) { static void gfx_d3d11_end_frame(void) {
SohImGui::Draw();
d3d.context->Flush(); d3d.context->Flush();
} }
@ -847,43 +752,13 @@ static void gfx_d3d11_finish_render(void) {
d3d.context->Flush(); d3d.context->Flush();
} }
void gfx_d3d11_resize_framebuffer(int fb, uint32_t width, uint32_t height) { int gfx_d3d11_create_framebuffer(void) {
FramebufferData& fd = d3d.framebuffers[fb];
TextureData& td = d3d.textures[fd.texture_id];
ComPtr<ID3D11Texture2D> texture, depth_stencil_texture;
D3D11_TEXTURE2D_DESC texture_desc;
texture_desc.Width = width;
texture_desc.Height = height;
texture_desc.Usage = D3D11_USAGE_DEFAULT;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0;
texture_desc.ArraySize = 1;
texture_desc.MipLevels = 1;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, texture.GetAddressOf()));
create_depth_stencil_objects(width, height, depth_stencil_texture.GetAddressOf(), fd.depth_stencil_view.ReleaseAndGetAddressOf(), nullptr);
ThrowIfFailed(d3d.device->CreateRenderTargetView(texture.Get(), nullptr, fd.render_target_view.ReleaseAndGetAddressOf()));
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), nullptr, td.resource_view.ReleaseAndGetAddressOf()));
td.width = width;
td.height = height;
}
int gfx_d3d11_create_framebuffer(uint32_t width, uint32_t height) {
uint32_t texture_id = gfx_d3d11_new_texture(); uint32_t texture_id = gfx_d3d11_new_texture();
TextureData& t = d3d.textures[texture_id]; TextureData& t = d3d.textures[texture_id];
t.width = width;
t.height = height;
size_t index = d3d.framebuffers.size(); size_t index = d3d.framebuffers.size();
d3d.framebuffers.resize(d3d.framebuffers.size() + 1); d3d.framebuffers.resize(d3d.framebuffers.size() + 1);
FramebufferData& data = d3d.framebuffers.back(); Framebuffer& data = d3d.framebuffers.back();
data.texture_id = texture_id; data.texture_id = texture_id;
uint32_t tile = 0; uint32_t tile = 0;
@ -892,24 +767,109 @@ int gfx_d3d11_create_framebuffer(uint32_t width, uint32_t height) {
gfx_d3d11_set_sampler_parameters(0, true, G_TX_WRAP, G_TX_WRAP); gfx_d3d11_set_sampler_parameters(0, true, G_TX_WRAP, G_TX_WRAP);
d3d.current_texture_ids[tile] = saved; d3d.current_texture_ids[tile] = saved;
gfx_d3d11_resize_framebuffer(index, width, height);
return (int)index; return (int)index;
} }
void gfx_d3d11_set_framebuffer(int fb) { static void gfx_d3d11_update_framebuffer_parameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, bool opengl_invert_y, bool render_target, bool has_depth_buffer, bool can_extract_depth) {
d3d.render_target_height = d3d.textures[d3d.framebuffers[fb].texture_id].height; Framebuffer& fb = d3d.framebuffers[fb_id];
TextureData& tex = d3d.textures[fb.texture_id];
d3d.context->OMSetRenderTargets(1, d3d.framebuffers[fb].render_target_view.GetAddressOf(), d3d.framebuffers[fb].depth_stencil_view.Get()); width = max(width, 1U);
height = max(height, 1U);
while (msaa_level > 1 && d3d.msaa_num_quality_levels[msaa_level - 1] == 0) {
--msaa_level;
}
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f }; bool diff = tex.width != width || tex.height != height || fb.msaa_level != msaa_level;
d3d.context->ClearRenderTargetView(d3d.framebuffers[fb].render_target_view.Get(), clearColor);
d3d.context->ClearDepthStencilView(d3d.framebuffers[fb].depth_stencil_view.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0); if (diff || (fb.render_target_view.Get() != nullptr) != render_target) {
if (fb_id != 0) {
D3D11_TEXTURE2D_DESC texture_desc;
texture_desc.Width = width;
texture_desc.Height = height;
texture_desc.Usage = D3D11_USAGE_DEFAULT;
texture_desc.BindFlags = (msaa_level <= 1 ? D3D11_BIND_SHADER_RESOURCE : 0) | (render_target ? D3D11_BIND_RENDER_TARGET : 0);
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0;
texture_desc.ArraySize = 1;
texture_desc.MipLevels = 1;
texture_desc.SampleDesc.Count = msaa_level;
texture_desc.SampleDesc.Quality = 0;
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, tex.texture.ReleaseAndGetAddressOf()));
if (msaa_level <= 1) {
ThrowIfFailed(d3d.device->CreateShaderResourceView(tex.texture.Get(), nullptr, tex.resource_view.ReleaseAndGetAddressOf()));
}
} else if (diff) {
DXGI_SWAP_CHAIN_DESC1 desc1;
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
if (desc1.Width != width || desc1.Height != height) {
fb.render_target_view.Reset();
tex.texture.Reset();
ThrowIfFailed(d3d.swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, desc1.Flags));
}
ThrowIfFailed(d3d.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)tex.texture.ReleaseAndGetAddressOf()));
}
if (render_target) {
ThrowIfFailed(d3d.device->CreateRenderTargetView(tex.texture.Get(), nullptr, fb.render_target_view.ReleaseAndGetAddressOf()));
}
tex.width = width;
tex.height = height;
}
if (has_depth_buffer && (diff || !fb.has_depth_buffer || (fb.depth_stencil_srv.Get() != nullptr) != can_extract_depth)) {
fb.depth_stencil_srv.Reset();
create_depth_stencil_objects(width, height, msaa_level, fb.depth_stencil_view.ReleaseAndGetAddressOf(), can_extract_depth ? fb.depth_stencil_srv.GetAddressOf() : nullptr);
}
if (!has_depth_buffer) {
fb.depth_stencil_view.Reset();
fb.depth_stencil_srv.Reset();
}
fb.has_depth_buffer = has_depth_buffer;
fb.msaa_level = msaa_level;
} }
void gfx_d3d11_reset_framebuffer(void) { void gfx_d3d11_start_draw_to_framebuffer(int fb_id, float noise_scale) {
d3d.render_target_height = d3d.current_height; Framebuffer& fb = d3d.framebuffers[fb_id];
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get()); d3d.render_target_height = d3d.textures[fb.texture_id].height;
d3d.context->OMSetRenderTargets(1, fb.render_target_view.GetAddressOf(), fb.has_depth_buffer ? fb.depth_stencil_view.Get() : nullptr);
d3d.current_framebuffer = fb_id;
if (noise_scale != 0.0f) {
d3d.per_frame_cb_data.noise_scale = 1.0f / noise_scale;
}
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);
}
void gfx_d3d11_clear_framebuffer(void) {
Framebuffer& fb = d3d.framebuffers[d3d.current_framebuffer];
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
d3d.context->ClearRenderTargetView(fb.render_target_view.Get(), clearColor);
if (fb.has_depth_buffer) {
d3d.context->ClearDepthStencilView(fb.depth_stencil_view.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
}
}
void gfx_d3d11_resolve_msaa_color_buffer(int fb_id_target, int fb_id_source) {
Framebuffer& fb_dst = d3d.framebuffers[fb_id_target];
Framebuffer& fb_src = d3d.framebuffers[fb_id_source];
d3d.context->ResolveSubresource(d3d.textures[fb_dst.texture_id].texture.Get(), 0, d3d.textures[fb_src.texture_id].texture.Get(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
}
void *gfx_d3d11_get_framebuffer_texture_id(int fb_id) {
return (void *)d3d.textures[d3d.framebuffers[fb_id].texture_id].resource_view.Get();
} }
void gfx_d3d11_select_texture_fb(int fbID) { void gfx_d3d11_select_texture_fb(int fbID) {
@ -917,62 +877,107 @@ void gfx_d3d11_select_texture_fb(int fbID) {
gfx_d3d11_select_texture(tile, d3d.framebuffers[fbID].texture_id); gfx_d3d11_select_texture(tile, d3d.framebuffers[fbID].texture_id);
} }
uint16_t gfx_d3d11_get_pixel_depth(float x, float y) { std::map<std::pair<float, float>, uint16_t> gfx_d3d11_get_pixel_depth(int fb_id, const std::set<std::pair<float, float>>& coordinates) {
Framebuffer& fb = d3d.framebuffers[fb_id];
TextureData& td = d3d.textures[fb.texture_id];
if (coordinates.size() > d3d.coord_buffer_size) {
d3d.coord_buffer.Reset();
d3d.coord_buffer_srv.Reset();
d3d.depth_value_output_buffer.Reset();
d3d.depth_value_output_uav.Reset();
d3d.depth_value_output_buffer_copy.Reset();
D3D11_BUFFER_DESC coord_buf_desc;
coord_buf_desc.Usage = D3D11_USAGE_DYNAMIC;
coord_buf_desc.ByteWidth = sizeof(Coord) * coordinates.size();
coord_buf_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
coord_buf_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
coord_buf_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
coord_buf_desc.StructureByteStride = sizeof(Coord);
ThrowIfFailed(d3d.device->CreateBuffer(&coord_buf_desc, nullptr, d3d.coord_buffer.GetAddressOf()));
D3D11_SHADER_RESOURCE_VIEW_DESC coord_buf_srv_desc;
coord_buf_srv_desc.Format = DXGI_FORMAT_UNKNOWN;
coord_buf_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
coord_buf_srv_desc.Buffer.FirstElement = 0;
coord_buf_srv_desc.Buffer.NumElements = coordinates.size();
ThrowIfFailed(d3d.device->CreateShaderResourceView(d3d.coord_buffer.Get(), &coord_buf_srv_desc, d3d.coord_buffer_srv.GetAddressOf()));
D3D11_BUFFER_DESC output_buffer_desc;
output_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
output_buffer_desc.ByteWidth = sizeof(float) * coordinates.size();
output_buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
output_buffer_desc.CPUAccessFlags = 0;
output_buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
output_buffer_desc.StructureByteStride = sizeof(float);
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer.GetAddressOf()));
D3D11_UNORDERED_ACCESS_VIEW_DESC output_buffer_uav_desc;
output_buffer_uav_desc.Format = DXGI_FORMAT_UNKNOWN;
output_buffer_uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
output_buffer_uav_desc.Buffer.FirstElement = 0;
output_buffer_uav_desc.Buffer.NumElements = coordinates.size();
output_buffer_uav_desc.Buffer.Flags = 0;
ThrowIfFailed(d3d.device->CreateUnorderedAccessView(d3d.depth_value_output_buffer.Get(), &output_buffer_uav_desc, d3d.depth_value_output_uav.GetAddressOf()));
output_buffer_desc.Usage = D3D11_USAGE_STAGING;
output_buffer_desc.BindFlags = 0;
output_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer_copy.GetAddressOf()));
d3d.coord_buffer_size = coordinates.size();
}
D3D11_MAPPED_SUBRESOURCE ms; D3D11_MAPPED_SUBRESOURCE ms;
if (fb.msaa_level > 1 && d3d.compute_shader_msaa.Get() == nullptr) {
ThrowIfFailed(d3d.device->CreateComputeShader(d3d.compute_shader_msaa_blob->GetBufferPointer(), d3d.compute_shader_msaa_blob->GetBufferSize(), nullptr, d3d.compute_shader_msaa.GetAddressOf()));
}
// ImGui overwrites these values, so we cannot set them once at init // ImGui overwrites these values, so we cannot set them once at init
d3d.context->CSSetShader(d3d.compute_shader.Get(), nullptr, 0); d3d.context->CSSetShader(fb.msaa_level > 1 ? d3d.compute_shader_msaa.Get() : d3d.compute_shader.Get(), nullptr, 0);
d3d.context->CSSetConstantBuffers(0, 1, d3d.coord_buffer.GetAddressOf());
d3d.context->CSSetSamplers(0, 1, d3d.depth_value_sampler.GetAddressOf());
d3d.context->CSSetUnorderedAccessViews(0, 1, d3d.depth_value_output_uav.GetAddressOf(), nullptr); d3d.context->CSSetUnorderedAccessViews(0, 1, d3d.depth_value_output_uav.GetAddressOf(), nullptr);
ThrowIfFailed(d3d.context->Map(d3d.coord_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms)); ThrowIfFailed(d3d.context->Map(d3d.coord_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms));
CoordCB* coord_cb = (CoordCB*)ms.pData; Coord *coord_cb = (Coord *)ms.pData;
coord_cb->x = x / d3d.current_width; {
// We invert y because the game assumes OpenGL coordinates (bottom-left corner is origin), while DX's origin is top-left corner size_t i = 0;
coord_cb->y = 1 - y / d3d.current_height; for (const auto& coord : coordinates) {
coord_cb[i].x = coord.first;
// We invert y because the gfx_pc assumes OpenGL coordinates (bottom-left corner is origin), while DX's origin is top-left corner
coord_cb[i].y = td.height - 1 - coord.second;
++i;
}
}
d3d.context->Unmap(d3d.coord_buffer.Get(), 0); d3d.context->Unmap(d3d.coord_buffer.Get(), 0);
// The depth stencil texture can only have one mapping at a time, so temporarily unbind from the OM // The depth stencil texture can only have one mapping at a time, so unbind from the OM
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), nullptr); ID3D11RenderTargetView* null_arr1[1] = { nullptr };
d3d.context->CSSetShaderResources(0, 1, d3d.depth_stencil_srv.GetAddressOf()); d3d.context->OMSetRenderTargets(1, null_arr1, nullptr);
d3d.context->Dispatch(1, 1, 1); ID3D11ShaderResourceView *srvs[] = { fb.depth_stencil_srv.Get(), d3d.coord_buffer_srv.Get() };
d3d.context->CSSetShaderResources(0, 2, srvs);
d3d.context->Dispatch(coordinates.size(), 1, 1);
d3d.context->CopyResource(d3d.depth_value_output_buffer_copy.Get(), d3d.depth_value_output_buffer.Get()); d3d.context->CopyResource(d3d.depth_value_output_buffer_copy.Get(), d3d.depth_value_output_buffer.Get());
ThrowIfFailed(d3d.context->Map(d3d.depth_value_output_buffer_copy.Get(), 0, D3D11_MAP_READ, 0, &ms)); ThrowIfFailed(d3d.context->Map(d3d.depth_value_output_buffer_copy.Get(), 0, D3D11_MAP_READ, 0, &ms));
float res = *(float *)ms.pData; std::map<std::pair<float, float>, uint16_t> res;
d3d.context->Unmap(d3d.depth_value_output_buffer_copy.Get(), 0); {
size_t i = 0;
ID3D11ShaderResourceView *null_arr[1] = { nullptr }; for (const auto& coord : coordinates) {
d3d.context->CSSetShaderResources(0, 1, null_arr); res.emplace(coord, ((float *)ms.pData)[i++] * 65532.0f);
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
return res * 65532.0f;
}
uint16_t gfx_d3d11_get_pixel_depth_old(float x, float y) {
// This approach, compared to using a compute shader, might have better performance on nvidia cards
if (!d3d.copied_depth_buffer) {
d3d.context->CopyResource(d3d.depth_stencil_copy_texture.Get(), d3d.depth_stencil_texture.Get());
d3d.copied_depth_buffer = true;
}
D3D11_MAPPED_SUBRESOURCE mapping_desc;
d3d.context->Map(d3d.depth_stencil_copy_texture.Get(), 0, D3D11_MAP_READ, 0, &mapping_desc);
float res = 0;
if (mapping_desc.pData != nullptr) {
float *addr = (float *)mapping_desc.pData;
uint32_t num_pixels = mapping_desc.DepthPitch / sizeof(float);
uint32_t width = mapping_desc.RowPitch / sizeof(float);
uint32_t height = width == 0 ? 0 : num_pixels / width;
if (x >= 0 && x < width && y >= 0 && y < height) {
res = addr[width * (height - 1 - (int)y) + (int)x];
} }
} }
d3d.context->Unmap(d3d.depth_stencil_copy_texture.Get(), 0); d3d.context->Unmap(d3d.depth_value_output_buffer_copy.Get(), 0);
return res * 65532.0f;
ID3D11ShaderResourceView *null_arr[2] = { nullptr, nullptr };
d3d.context->CSSetShaderResources(0, 2, null_arr);
return res;
} }
} // namespace } // namespace
@ -982,7 +987,7 @@ ImTextureID SohImGui::GetTextureByID(int id) {
} }
struct GfxRenderingAPI gfx_direct3d11_api = { struct GfxRenderingAPI gfx_direct3d11_api = {
gfx_d3d11_z_is_from_0_to_1, gfx_d3d11_get_clip_parameters,
gfx_d3d11_unload_shader, gfx_d3d11_unload_shader,
gfx_d3d11_load_shader, gfx_d3d11_load_shader,
gfx_d3d11_create_and_load_new_shader, gfx_d3d11_create_and_load_new_shader,
@ -993,7 +998,6 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
gfx_d3d11_upload_texture, gfx_d3d11_upload_texture,
gfx_d3d11_set_sampler_parameters, gfx_d3d11_set_sampler_parameters,
gfx_d3d11_set_depth_test_and_mask, gfx_d3d11_set_depth_test_and_mask,
gfx_d3d11_get_pixel_depth,
gfx_d3d11_set_zmode_decal, gfx_d3d11_set_zmode_decal,
gfx_d3d11_set_viewport, gfx_d3d11_set_viewport,
gfx_d3d11_set_scissor, gfx_d3d11_set_scissor,
@ -1005,9 +1009,12 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
gfx_d3d11_end_frame, gfx_d3d11_end_frame,
gfx_d3d11_finish_render, gfx_d3d11_finish_render,
gfx_d3d11_create_framebuffer, gfx_d3d11_create_framebuffer,
gfx_d3d11_resize_framebuffer, gfx_d3d11_update_framebuffer_parameters,
gfx_d3d11_set_framebuffer, gfx_d3d11_start_draw_to_framebuffer,
gfx_d3d11_reset_framebuffer, gfx_d3d11_clear_framebuffer,
gfx_d3d11_resolve_msaa_color_buffer,
gfx_d3d11_get_pixel_depth,
gfx_d3d11_get_framebuffer_texture_id,
gfx_d3d11_select_texture_fb, gfx_d3d11_select_texture_fb,
gfx_d3d11_delete_texture gfx_d3d11_delete_texture
}; };

View File

@ -134,9 +134,6 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
} }
} }
} }
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, " float4 screenPos : TEXCOORD2;");
}
if (cc_features.opt_fog) { if (cc_features.opt_fog) {
append_line(buf, &len, " float4 fog : FOG;"); append_line(buf, &len, " float4 fog : FOG;");
num_floats += 4; num_floats += 4;
@ -163,7 +160,7 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
if (cc_features.opt_alpha && cc_features.opt_noise) { if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, "cbuffer PerFrameCB : register(b0) {"); append_line(buf, &len, "cbuffer PerFrameCB : register(b0) {");
append_line(buf, &len, " uint noise_frame;"); append_line(buf, &len, " uint noise_frame;");
append_line(buf, &len, " float2 noise_scale;"); append_line(buf, &len, " float noise_scale;");
append_line(buf, &len, "}"); append_line(buf, &len, "}");
append_line(buf, &len, "float random(in float3 value) {"); append_line(buf, &len, "float random(in float3 value) {");
@ -217,9 +214,6 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
append_line(buf, &len, ") {"); append_line(buf, &len, ") {");
append_line(buf, &len, " PSInput result;"); append_line(buf, &len, " PSInput result;");
append_line(buf, &len, " result.position = position;"); append_line(buf, &len, " result.position = position;");
if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, " result.screenPos = position;");
}
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (cc_features.used_textures[i]) { if (cc_features.used_textures[i]) {
len += sprintf(buf + len, " result.uv%d = uv%d;\r\n", i, i); len += sprintf(buf + len, " result.uv%d = uv%d;\r\n", i, i);
@ -244,7 +238,11 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
if (include_root_signature) { if (include_root_signature) {
append_line(buf, &len, "[RootSignature(RS)]"); append_line(buf, &len, "[RootSignature(RS)]");
} }
append_line(buf, &len, "float4 PSMain(PSInput input) : SV_TARGET {"); if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(buf, &len, "float4 PSMain(PSInput input, float4 screenSpace : SV_Position) : SV_TARGET {");
} else {
append_line(buf, &len, "float4 PSMain(PSInput input) : SV_TARGET {");
}
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (cc_features.used_textures[i]) { if (cc_features.used_textures[i]) {
len += sprintf(buf + len, " float2 tc%d = input.uv%d;\r\n", i, i); len += sprintf(buf + len, " float2 tc%d = input.uv%d;\r\n", i, i);
@ -301,7 +299,7 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
} }
if (cc_features.opt_alpha && cc_features.opt_noise) { 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, " float2 coords = screenSpace.xy * noise_scale;");
append_line(buf, &len, " texel.a *= round(saturate(random(float3(floor(coords), noise_frame)) + texel.a - 0.5));"); append_line(buf, &len, " texel.a *= round(saturate(random(float3(floor(coords), noise_frame)) + texel.a - 0.5));");
} }

View File

@ -10,6 +10,7 @@
#include <windows.h> #include <windows.h>
#include <wrl/client.h> #include <wrl/client.h>
#include <dxgi1_3.h> #include <dxgi1_3.h>
#include <dxgi1_4.h>
#include <versionhelpers.h> #include <versionhelpers.h>
#include <shellscalingapi.h> #include <shellscalingapi.h>
@ -61,6 +62,7 @@ static struct {
RECT last_window_rect; RECT last_window_rect;
bool is_full_screen, last_maximized_state; bool is_full_screen, last_maximized_state;
bool dxgi1_4;
ComPtr<IDXGIFactory2> factory; ComPtr<IDXGIFactory2> factory;
ComPtr<IDXGISwapChain1> swap_chain; ComPtr<IDXGISwapChain1> swap_chain;
HANDLE waitable_object; HANDLE waitable_object;
@ -197,17 +199,6 @@ static void toggle_borderless_window_full_screen(bool enable, bool call_callback
} }
} }
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;
}
}
static void onkeydown(WPARAM w_param, LPARAM l_param) { static void onkeydown(WPARAM w_param, LPARAM l_param) {
int key = ((l_param >> 16) & 0x1ff); int key = ((l_param >> 16) & 0x1ff);
if (dxgi.on_key_down != nullptr) { if (dxgi.on_key_down != nullptr) {
@ -227,7 +218,8 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par
SohImGui::Update(event_impl); SohImGui::Update(event_impl);
switch (message) { switch (message) {
case WM_SIZE: case WM_SIZE:
gfx_dxgi_on_resize(); dxgi.current_width = (uint32_t)(l_param & 0xffff);
dxgi.current_height = (uint32_t)(l_param >> 16);
break; break;
case WM_DESTROY: case WM_DESTROY:
exit(0); exit(0);
@ -573,6 +565,13 @@ void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*crea
ThrowIfFailed(dxgi.CreateDXGIFactory1(__uuidof(IDXGIFactory2), &dxgi.factory)); ThrowIfFailed(dxgi.CreateDXGIFactory1(__uuidof(IDXGIFactory2), &dxgi.factory));
} }
{
ComPtr<IDXGIFactory4> factory4;
if (dxgi.factory->QueryInterface(__uuidof(IDXGIFactory4), &factory4) == S_OK) {
dxgi.dxgi1_4 = true;
}
}
ComPtr<IDXGIAdapter1> adapter; ComPtr<IDXGIAdapter1> adapter;
for (UINT i = 0; dxgi.factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) { for (UINT i = 0; dxgi.factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) {
DXGI_ADAPTER_DESC1 desc; DXGI_ADAPTER_DESC1 desc;
@ -604,7 +603,9 @@ ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device) {
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.Scaling = win8 ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH; 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.SwapEffect = dxgi.dxgi1_4 ?
DXGI_SWAP_EFFECT_FLIP_DISCARD : // Introduced in DXGI 1.4 and Windows 10
DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // Apparently flip sequential was also backported to Win 7 Platform Update
swap_chain_desc.Flags = dxgi_13 ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0; swap_chain_desc.Flags = dxgi_13 ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0;
swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.SampleDesc.Count = 1;

View File

@ -52,19 +52,33 @@ struct ShaderProgram {
uint8_t num_attribs; uint8_t num_attribs;
bool used_noise; bool used_noise;
GLint frame_count_location; GLint frame_count_location;
GLint window_height_location; GLint noise_scale_location;
};
struct Framebuffer {
uint32_t width, height;
bool has_depth_buffer;
uint32_t msaa_level;
bool invert_y;
GLuint fbo, clrbuf, clrbuf_msaa, rbo;
}; };
static map<pair<uint64_t, uint32_t>, struct ShaderProgram> shader_program_pool; static map<pair<uint64_t, uint32_t>, struct ShaderProgram> shader_program_pool;
static GLuint opengl_vbo; static GLuint opengl_vbo;
static uint32_t frame_count;
static uint32_t current_height;
static map<int, pair<GLuint, GLuint>> fb2tex;
static bool current_depth_mask; static bool current_depth_mask;
static bool gfx_opengl_z_is_from_0_to_1(void) { static uint32_t frame_count;
return false;
static vector<Framebuffer> framebuffers;
static size_t current_framebuffer;
static float current_noise_scale;
GLuint pixel_depth_rb, pixel_depth_fb;
size_t pixel_depth_rb_size;
static struct GfxClipParameters gfx_opengl_get_clip_parameters(void) {
return { false, framebuffers[current_framebuffer].invert_y };
} }
static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) { static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
@ -81,7 +95,7 @@ static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
static void gfx_opengl_set_uniforms(struct ShaderProgram *prg) { static void gfx_opengl_set_uniforms(struct ShaderProgram *prg) {
if (prg->used_noise) { if (prg->used_noise) {
glUniform1i(prg->frame_count_location, frame_count); glUniform1i(prg->frame_count_location, frame_count);
glUniform1i(prg->window_height_location, current_height); glUniform1f(prg->noise_scale_location, current_noise_scale);
} }
} }
@ -277,7 +291,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
if (cc_features.opt_alpha && cc_features.opt_noise) { if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(fs_buf, &fs_len, "uniform int frame_count;"); append_line(fs_buf, &fs_len, "uniform int frame_count;");
append_line(fs_buf, &fs_len, "uniform int window_height;"); append_line(fs_buf, &fs_len, "uniform float noise_scale;");
append_line(fs_buf, &fs_len, "float random(in vec3 value) {"); append_line(fs_buf, &fs_len, "float random(in vec3 value) {");
append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));"); append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));");
@ -338,7 +352,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
} }
if (cc_features.opt_alpha && cc_features.opt_noise) { if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * (240.0 / float(window_height))), float(frame_count))) + texel.a, 0.0, 1.0));"); append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + texel.a, 0.0, 1.0));");
} }
if (cc_features.opt_alpha) { if (cc_features.opt_alpha) {
@ -460,7 +474,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
if (cc_features.opt_alpha && cc_features.opt_noise) { if (cc_features.opt_alpha && cc_features.opt_noise) {
prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count"); prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count");
prg->window_height_location = glGetUniformLocation(shader_program, "window_height"); prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale");
prg->used_noise = true; prg->used_noise = true;
} else { } else {
prg->used_noise = false; prg->used_noise = false;
@ -496,7 +510,7 @@ static void gfx_opengl_select_texture(int tile, GLuint texture_id) {
} }
static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) { static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf);
} }
static uint32_t gfx_cm_to_opengl(uint32_t val) { static uint32_t gfx_cm_to_opengl(uint32_t val) {
@ -543,7 +557,6 @@ static void gfx_opengl_set_zmode_decal(bool zmode_decal) {
static void gfx_opengl_set_viewport(int x, int y, int width, int height) { static void gfx_opengl_set_viewport(int x, int y, int width, int height) {
glViewport(x, y, width, height); glViewport(x, y, width, height);
current_height = height;
} }
static void gfx_opengl_set_scissor(int x, int y, int width, int height) { static void gfx_opengl_set_scissor(int x, int y, int width, int height) {
@ -564,10 +577,6 @@ static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_
glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris); glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris);
} }
static unsigned int framebuffer;
static unsigned int textureColorbuffer;
static unsigned int rbo;
static void gfx_opengl_init(void) { static void gfx_opengl_init(void) {
//#if FOR_WINDOWS //#if FOR_WINDOWS
glewInit(); glewInit();
@ -576,143 +585,214 @@ static void gfx_opengl_init(void) {
glGenBuffers(1, &opengl_vbo); glGenBuffers(1, &opengl_vbo);
glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo);
glGenFramebuffers(1, &framebuffer);
glGenTextures(1, &textureColorbuffer);
glGenRenderbuffers(1, &rbo);
SohUtils::saveEnvironmentVar("framebuffer", std::to_string(textureColorbuffer));
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
framebuffers.resize(1); // for the default screen buffer
glGenRenderbuffers(1, &pixel_depth_rb);
glBindRenderbuffer(GL_RENDERBUFFER, pixel_depth_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1, 1);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &pixel_depth_fb);
glBindFramebuffer(GL_FRAMEBUFFER, pixel_depth_fb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, pixel_depth_rb);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
pixel_depth_rb_size = 1;
} }
static void gfx_opengl_on_resize(void) { static void gfx_opengl_on_resize(void) {
} }
static void gfx_opengl_start_frame(void) { static void gfx_opengl_start_frame(void) {
GLsizei framebuffer_width = gfx_current_dimensions.width;
GLsizei framebuffer_height = gfx_current_dimensions.height;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
std::shared_ptr<Ship::Window> wnd = Ship::GlobalCtx2::GetInstance()->GetWindow();
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer_width, framebuffer_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, framebuffer_width, framebuffer_height); // use a single renderbuffer object for both a depth AND stencil buffer.
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
frame_count++; frame_count++;
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_TRUE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glEnable(GL_DEPTH_CLAMP);
current_depth_mask = true;
} }
static void gfx_opengl_end_frame(void) { static void gfx_opengl_end_frame(void) {
glFlush();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLint last_program;
glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
glUseProgram(0);
SohImGui::Draw();
glUseProgram(last_program);
} }
static void gfx_opengl_finish_render(void) { static void gfx_opengl_finish_render(void) {
} }
static int gfx_opengl_create_framebuffer(uint32_t width, uint32_t height) { static int gfx_opengl_create_framebuffer() {
GLuint textureColorbuffer; GLuint clrbuf;
glGenTextures(1, &clrbuf);
glGenTextures(1, &textureColorbuffer); glBindTexture(GL_TEXTURE_2D, clrbuf);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
GLuint clrbuf_msaa;
glGenRenderbuffers(1, &clrbuf_msaa);
GLuint rbo; GLuint rbo;
glGenRenderbuffers(1, &rbo); glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1, 1);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
GLuint fbo; GLuint fbo;
glGenFramebuffers(1, &fbo); glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0); size_t i = framebuffers.size();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); framebuffers.resize(i + 1);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
fb2tex[fbo] = make_pair(textureColorbuffer, rbo); framebuffers[i].fbo = fbo;
framebuffers[i].clrbuf = clrbuf;
//glBindFramebuffer(GL_FRAMEBUFFER, 0); framebuffers[i].clrbuf_msaa = clrbuf_msaa;
framebuffers[i].rbo = rbo;
return fbo; return fbo;
} }
static void gfx_opengl_resize_framebuffer(int fb, uint32_t width, uint32_t height) { static void gfx_opengl_update_framebuffer_parameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, bool opengl_invert_y, bool render_target, bool has_depth_buffer, bool can_extract_depth) {
glBindTexture(GL_TEXTURE_2D, fb2tex[fb].first); Framebuffer& fb = framebuffers[fb_id];
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, fb2tex[fb].second); width = max(width, 1U);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); height = max(height, 1U);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
if (fb_id != 0) {
if (fb.width != width || fb.height != height || fb.msaa_level != msaa_level) {
if (msaa_level <= 1) {
glBindTexture(GL_TEXTURE_2D, fb.clrbuf);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.clrbuf, 0);
} else {
glBindRenderbuffer(GL_RENDERBUFFER, fb.clrbuf_msaa);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, GL_RGB8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fb.clrbuf_msaa);
}
}
if (has_depth_buffer && (fb.width != width || fb.height != height || fb.msaa_level != msaa_level || !fb.has_depth_buffer)) {
glBindRenderbuffer(GL_RENDERBUFFER, fb.rbo);
if (msaa_level <= 1) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
} else {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, GL_DEPTH24_STENCIL8, width, height);
}
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
if (!fb.has_depth_buffer && has_depth_buffer) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.rbo);
} else if (fb.has_depth_buffer && !has_depth_buffer) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
}
}
fb.width = width;
fb.height = height;
fb.has_depth_buffer = has_depth_buffer;
fb.msaa_level = msaa_level;
fb.invert_y = opengl_invert_y;
} }
void gfx_opengl_set_framebuffer(int fb) void gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) {
{ Framebuffer& fb = framebuffers[fb_id];
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) {
// Set origin to upper left corner, to match N64 and DX11
// If this function is not supported, the texture will be upside down :(
glClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
}
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb);
if (noise_scale != 0.0f) {
current_noise_scale = 1.0f / noise_scale;
}
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
current_framebuffer = fb_id;
}
void gfx_opengl_clear_framebuffer() {
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE); glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE);
glEnable(GL_SCISSOR_TEST);
} }
void gfx_opengl_reset_framebuffer(void) void gfx_opengl_resolve_msaa_color_buffer(int fb_id_target, int fb_id_source) {
{ Framebuffer& fb_dst = framebuffers[fb_id_target];
glBindFramebuffer(GL_FRAMEBUFFER, 0); Framebuffer& fb_src = framebuffers[fb_id_source];
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_dst.fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_src.fbo);
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) { glBlitFramebuffer(0, 0, fb_src.width, fb_src.height, 0, 0, fb_dst.width, fb_dst.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); glBindFramebuffer(GL_FRAMEBUFFER, current_framebuffer);
}
} }
void gfx_opengl_select_texture_fb(int fbID) void *gfx_opengl_get_framebuffer_texture_id(int fb_id) {
{ return (void *)(uintptr_t)framebuffers[fb_id].clrbuf;
}
void gfx_opengl_select_texture_fb(int fb_id) {
//glDisable(GL_DEPTH_TEST); //glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0 + 0); glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, fb2tex[fbID].first); glBindTexture(GL_TEXTURE_2D, framebuffers[fb_id].clrbuf);
} }
static uint16_t gfx_opengl_get_pixel_depth(float x, float y) { static std::map<std::pair<float, float>, uint16_t> gfx_opengl_get_pixel_depth(int fb_id, const std::set<std::pair<float, float>>& coordinates) {
float depth; std::map<std::pair<float, float>, uint16_t> res;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); Framebuffer& fb = framebuffers[fb_id];
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return depth * 65532.0f; if (coordinates.size() == 1) {
uint32_t depth_stencil_value;
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
int x = coordinates.begin()->first;
int y = coordinates.begin()->second;
glReadPixels(x, fb.invert_y ? fb.height - y : y, 1, 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, &depth_stencil_value);
res.emplace(*coordinates.begin(), (depth_stencil_value >> 18) << 2);
} else {
if (pixel_depth_rb_size < coordinates.size()) {
glBindRenderbuffer(GL_RENDERBUFFER, pixel_depth_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, coordinates.size(), 1);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
pixel_depth_rb_size = coordinates.size();
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pixel_depth_fb);
glDisable(GL_SCISSOR_TEST); // needed for the blit operation
{
size_t i = 0;
for (const auto& coord : coordinates) {
int x = coord.first;
int y = coord.second;
if (fb.invert_y) {
y = fb.height - y;
}
glBlitFramebuffer(x, y, x + 1, y + 1, i, 0, i + 1, 1, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
++i;
}
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, pixel_depth_fb);
vector<uint32_t> depth_stencil_values(coordinates.size());
glReadPixels(0, 0, coordinates.size(), 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depth_stencil_values.data());
{
size_t i = 0;
for (const auto& coord : coordinates) {
res.emplace(coord, (depth_stencil_values[i++] >> 18) << 2);
}
}
}
glBindFramebuffer(GL_FRAMEBUFFER, current_framebuffer);
return res;
} }
struct GfxRenderingAPI gfx_opengl_api = { struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_z_is_from_0_to_1, gfx_opengl_get_clip_parameters,
gfx_opengl_unload_shader, gfx_opengl_unload_shader,
gfx_opengl_load_shader, gfx_opengl_load_shader,
gfx_opengl_create_and_load_new_shader, gfx_opengl_create_and_load_new_shader,
@ -723,7 +803,6 @@ struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_upload_texture, gfx_opengl_upload_texture,
gfx_opengl_set_sampler_parameters, gfx_opengl_set_sampler_parameters,
gfx_opengl_set_depth_test_and_mask, gfx_opengl_set_depth_test_and_mask,
gfx_opengl_get_pixel_depth,
gfx_opengl_set_zmode_decal, gfx_opengl_set_zmode_decal,
gfx_opengl_set_viewport, gfx_opengl_set_viewport,
gfx_opengl_set_scissor, gfx_opengl_set_scissor,
@ -735,9 +814,12 @@ struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_end_frame, gfx_opengl_end_frame,
gfx_opengl_finish_render, gfx_opengl_finish_render,
gfx_opengl_create_framebuffer, gfx_opengl_create_framebuffer,
gfx_opengl_resize_framebuffer, gfx_opengl_update_framebuffer_parameters,
gfx_opengl_set_framebuffer, gfx_opengl_start_draw_to_framebuffer,
gfx_opengl_reset_framebuffer, gfx_opengl_clear_framebuffer,
gfx_opengl_resolve_msaa_color_buffer,
gfx_opengl_get_pixel_depth,
gfx_opengl_get_framebuffer_texture_id,
gfx_opengl_select_texture_fb, gfx_opengl_select_texture_fb,
gfx_opengl_delete_texture gfx_opengl_delete_texture
}; };

View File

@ -7,6 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <map> #include <map>
#include <set>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -27,6 +28,8 @@
#include "../../luslog.h" #include "../../luslog.h"
#include "../StrHash64.h" #include "../StrHash64.h"
#include "../../SohImGuiImpl.h"
#include "../../Environment.h"
// OTRTODO: fix header files for these // OTRTODO: fix header files for these
extern "C" { extern "C" {
@ -71,10 +74,6 @@ struct RGBA {
uint8_t r, g, b, a; uint8_t r, g, b, a;
}; };
struct XYWidthHeight {
uint16_t x, y, width, height;
};
struct LoadedVertex { struct LoadedVertex {
float x, y, z, w; float x, y, z, w;
float u, v; float u, v;
@ -174,8 +173,16 @@ static struct RenderingState {
TextureCacheNode *textures[2]; TextureCacheNode *textures[2];
} rendering_state; } rendering_state;
struct GfxDimensions gfx_current_window_dimensions;
struct GfxDimensions gfx_current_dimensions; struct GfxDimensions gfx_current_dimensions;
static struct GfxDimensions gfx_prev_dimensions; static struct GfxDimensions gfx_prev_dimensions;
struct XYWidthHeight gfx_current_game_window_viewport;
static bool game_renders_to_framebuffer;
static int game_framebuffer;
static int game_framebuffer_msaa_resolved;
uint32_t gfx_msaa_level = 1;
static bool dropped_frame; static bool dropped_frame;
@ -198,6 +205,9 @@ static bool fbActive = 0;
static map<int, FBInfo>::iterator active_fb; static map<int, FBInfo>::iterator active_fb;
static map<int, FBInfo> framebuffers; static map<int, FBInfo> framebuffers;
static set<pair<float, float>> get_pixel_depth_pending;
static map<pair<float, float>, uint16_t> get_pixel_depth_cached;
#ifdef _MSC_VER #ifdef _MSC_VER
// TODO: Properly implement for MSVC // TODO: Properly implement for MSVC
static unsigned long get_time(void) static unsigned long get_time(void)
@ -1326,11 +1336,11 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
gfx_rapi->shader_get_info(prg, &num_inputs, used_textures); gfx_rapi->shader_get_info(prg, &num_inputs, used_textures);
bool z_is_from_0_to_1 = gfx_rapi->z_is_from_0_to_1(); struct GfxClipParameters clip_parameters = gfx_rapi->get_clip_parameters();
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
float z = v_arr[i]->z, w = v_arr[i]->w; float z = v_arr[i]->z, w = v_arr[i]->w;
if (z_is_from_0_to_1) { if (clip_parameters.z_is_from_0_to_1) {
z = (z + w) / 2.0f; z = (z + w) / 2.0f;
} }
@ -1340,7 +1350,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
} }
buf_vbo[buf_vbo_len++] = v_arr[i]->x; buf_vbo[buf_vbo_len++] = v_arr[i]->x;
buf_vbo[buf_vbo_len++] = v_arr[i]->y; buf_vbo[buf_vbo_len++] = clip_parameters.invert_y ? -v_arr[i]->y : v_arr[i]->y;
buf_vbo[buf_vbo_len++] = z; buf_vbo[buf_vbo_len++] = z;
buf_vbo[buf_vbo_len++] = w; buf_vbo[buf_vbo_len++] = w;
@ -1491,6 +1501,27 @@ static void gfx_sp_geometry_mode(uint32_t clear, uint32_t set) {
rsp.geometry_mode |= set; rsp.geometry_mode |= set;
} }
static void gfx_adjust_viewport_or_scissor(XYWidthHeight *area) {
if (!fbActive) {
area->width *= RATIO_X;
area->height *= RATIO_Y;
area->x *= RATIO_X;
area->y = SCREEN_HEIGHT - area->y;
area->y *= RATIO_Y;
if (!game_renders_to_framebuffer || (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
area->x += gfx_current_game_window_viewport.x;
area->y += gfx_current_window_dimensions.height - (gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
}
} else {
area->width *= RATIO_Y;
area->height *= RATIO_Y;
area->x *= RATIO_Y;
area->y = active_fb->second.orig_height - area->y;
area->y *= RATIO_Y;
}
}
static void gfx_calc_and_set_viewport(const Vp_t *viewport) { static void gfx_calc_and_set_viewport(const Vp_t *viewport) {
// 2 bits fraction // 2 bits fraction
float width = 2.0f * viewport->vscale[0] / 4.0f; float width = 2.0f * viewport->vscale[0] / 4.0f;
@ -1498,25 +1529,13 @@ static void gfx_calc_and_set_viewport(const Vp_t *viewport) {
float x = (viewport->vtrans[0] / 4.0f) - width / 2.0f; float x = (viewport->vtrans[0] / 4.0f) - width / 2.0f;
float y = ((viewport->vtrans[1] / 4.0f) + height / 2.0f); float y = ((viewport->vtrans[1] / 4.0f) + height / 2.0f);
if (!fbActive) {
width *= RATIO_X;
height *= RATIO_Y;
x *= RATIO_X;
y = SCREEN_HEIGHT - y;
y *= RATIO_Y;
} else {
width *= RATIO_Y;
height *= RATIO_Y;
x *= RATIO_Y;
y = active_fb->second.orig_height - y;
y *= RATIO_Y;
}
rdp.viewport.x = x; rdp.viewport.x = x;
rdp.viewport.y = y; rdp.viewport.y = y;
rdp.viewport.width = width; rdp.viewport.width = width;
rdp.viewport.height = height; rdp.viewport.height = height;
gfx_adjust_viewport_or_scissor(&rdp.viewport);
rdp.viewport_or_scissor_changed = true; rdp.viewport_or_scissor_changed = true;
} }
@ -1585,11 +1604,6 @@ static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile
rdp.textures_changed[1] = true; rdp.textures_changed[1] = true;
} }
if (tile > 8)
{
int bp = 0;
}
rdp.first_tile_index = tile; rdp.first_tile_index = tile;
} }
@ -1599,25 +1613,13 @@ static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32
float width = (lrx - ulx) / 4.0f; float width = (lrx - ulx) / 4.0f;
float height = (lry - uly) / 4.0f; float height = (lry - uly) / 4.0f;
if (!fbActive) {
x *= RATIO_X;
y = SCREEN_HEIGHT - y;
y *= RATIO_Y;
width *= RATIO_X;
height *= RATIO_Y;
} else {
width *= RATIO_Y;
height *= RATIO_Y;
x *= RATIO_Y;
y = active_fb->second.orig_height - y;
y *= RATIO_Y;
}
rdp.scissor.x = x; rdp.scissor.x = x;
rdp.scissor.y = y; rdp.scissor.y = y;
rdp.scissor.width = width; rdp.scissor.width = width;
rdp.scissor.height = height; rdp.scissor.height = height;
gfx_adjust_viewport_or_scissor(&rdp.scissor);
rdp.viewport_or_scissor_changed = true; rdp.viewport_or_scissor_changed = true;
} }
@ -1887,10 +1889,12 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr
ur->w = 1.0f; ur->w = 1.0f;
// The coordinates for texture rectangle shall bypass the viewport setting // The coordinates for texture rectangle shall bypass the viewport setting
struct XYWidthHeight default_viewport = { 0, 0, gfx_current_dimensions.width, gfx_current_dimensions.height }; struct XYWidthHeight default_viewport = { 0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT };
struct XYWidthHeight viewport_saved = rdp.viewport; struct XYWidthHeight viewport_saved = rdp.viewport;
uint32_t geometry_mode_saved = rsp.geometry_mode; uint32_t geometry_mode_saved = rsp.geometry_mode;
gfx_adjust_viewport_or_scissor(&default_viewport);
rdp.viewport = default_viewport; rdp.viewport = default_viewport;
rdp.viewport_or_scissor_changed = true; rdp.viewport_or_scissor_changed = true;
rsp.geometry_mode = 0; rsp.geometry_mode = 0;
@ -2456,14 +2460,15 @@ static void gfx_run_dl(Gfx* cmd) {
gfx_flush(); gfx_flush();
fbActive = 1; fbActive = 1;
active_fb = framebuffers.find(cmd->words.w1); active_fb = framebuffers.find(cmd->words.w1);
gfx_rapi->set_framebuffer(active_fb->first); gfx_rapi->start_draw_to_framebuffer(active_fb->first, (float)active_fb->second.applied_height / active_fb->second.orig_height);
gfx_rapi->clear_framebuffer();
} }
break; break;
case G_RESETFB: case G_RESETFB:
{ {
gfx_flush(); gfx_flush();
fbActive = 0; fbActive = 0;
gfx_rapi->reset_framebuffer(); gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
break; break;
} }
break; break;
@ -2547,7 +2552,7 @@ static void gfx_run_dl(Gfx* cmd) {
gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP); gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP);
break; break;
} }
case G_TEXRECT_WIDE: case G_TEXRECT_WIDE:
{ {
int32_t lrx, lry, tile, ulx, uly; int32_t lrx, lry, tile, ulx, uly;
uint32_t uls, ult, dsdx, dtdy; uint32_t uls, ult, dsdx, dtdy;
@ -2630,9 +2635,12 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co
gfx_rapi = rapi; gfx_rapi = rapi;
gfx_wapi->init(game_name, start_in_fullscreen); gfx_wapi->init(game_name, start_in_fullscreen);
gfx_rapi->init(); gfx_rapi->init();
gfx_rapi->update_framebuffer_parameters(0, SCREEN_WIDTH, SCREEN_HEIGHT, 1, false, true, true, true);
gfx_current_dimensions.internal_mul = 1; gfx_current_dimensions.internal_mul = 1;
gfx_current_dimensions.width = SCREEN_WIDTH; gfx_current_dimensions.width = SCREEN_WIDTH;
gfx_current_dimensions.height = SCREEN_HEIGHT; gfx_current_dimensions.height = SCREEN_HEIGHT;
game_framebuffer = gfx_rapi->create_framebuffer();
game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer();
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
segmentPointers[i] = NULL; segmentPointers[i] = NULL;
@ -2681,7 +2689,8 @@ struct GfxRenderingAPI *gfx_get_current_rendering_api(void) {
void gfx_start_frame(void) { void gfx_start_frame(void) {
gfx_wapi->handle_events(); gfx_wapi->handle_events();
// gfx_wapi->get_dimensions(&gfx_current_dimensions.width, &gfx_current_dimensions.height); gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height);
SohImGui::DrawMainMenuAndCalculateGameSize();
if (gfx_current_dimensions.height == 0) { if (gfx_current_dimensions.height == 0) {
// Avoid division by zero // Avoid division by zero
gfx_current_dimensions.height = 1; gfx_current_dimensions.height = 1;
@ -2693,7 +2702,7 @@ void gfx_start_frame(void) {
uint32_t width = fb.second.orig_width, height = fb.second.orig_height; uint32_t width = fb.second.orig_width, height = fb.second.orig_height;
gfx_adjust_width_height_for_scale(width, height); gfx_adjust_width_height_for_scale(width, height);
if (width != fb.second.applied_width || height != fb.second.applied_height) { if (width != fb.second.applied_width || height != fb.second.applied_height) {
gfx_rapi->resize_framebuffer(fb.first, width, height); gfx_rapi->update_framebuffer_parameters(fb.first, width, height, 1, true, true, true, true);
fb.second.applied_width = width; fb.second.applied_width = width;
fb.second.applied_height = height; fb.second.applied_height = height;
} }
@ -2701,6 +2710,22 @@ void gfx_start_frame(void) {
} }
gfx_prev_dimensions = gfx_current_dimensions; gfx_prev_dimensions = gfx_current_dimensions;
bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || gfx_current_dimensions.height != gfx_current_game_window_viewport.height;
if (different_size || gfx_msaa_level > 1) {
game_renders_to_framebuffer = true;
if (different_size) {
gfx_rapi->update_framebuffer_parameters(game_framebuffer, gfx_current_dimensions.width, gfx_current_dimensions.height, gfx_msaa_level, true, true, true, true);
} else {
// MSAA framebuffer needs to be resolved to an equally sized target when complete, which must therefore match the window size
gfx_rapi->update_framebuffer_parameters(game_framebuffer, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, gfx_msaa_level, false, true, true, true);
}
if (gfx_msaa_level > 1 && different_size) {
gfx_rapi->update_framebuffer_parameters(game_framebuffer_msaa_resolved, gfx_current_dimensions.width, gfx_current_dimensions.height, 1, false, false, false, false);
}
} else {
game_renders_to_framebuffer = false;
}
fbActive = 0; fbActive = 0;
} }
@ -2708,17 +2733,44 @@ void gfx_run(Gfx *commands) {
gfx_sp_reset(); gfx_sp_reset();
//puts("New frame"); //puts("New frame");
get_pixel_depth_pending.clear();
get_pixel_depth_cached.clear();
if (!gfx_wapi->start_frame()) { if (!gfx_wapi->start_frame()) {
dropped_frame = true; dropped_frame = true;
SohImGui::DrawFramebufferAndGameInput();
SohImGui::CancelFrame();
return; return;
} }
dropped_frame = false; dropped_frame = false;
double t0 = gfx_wapi->get_time(); double t0 = gfx_wapi->get_time();
gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, 1, false, true, true, !game_renders_to_framebuffer);
gfx_rapi->start_frame(); gfx_rapi->start_frame();
gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
gfx_rapi->clear_framebuffer();
gfx_run_dl(commands); gfx_run_dl(commands);
gfx_flush(); gfx_flush();
SohUtils::saveEnvironmentVar("framebuffer", string());
if (game_renders_to_framebuffer) {
gfx_rapi->start_draw_to_framebuffer(0, 1);
gfx_rapi->clear_framebuffer();
if (gfx_msaa_level > 1) {
bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || gfx_current_dimensions.height != gfx_current_game_window_viewport.height;
if (different_size) {
gfx_rapi->resolve_msaa_color_buffer(game_framebuffer_msaa_resolved, game_framebuffer);
SohUtils::saveEnvironmentVar("framebuffer", std::to_string((uintptr_t)gfx_rapi->get_framebuffer_texture_id(game_framebuffer_msaa_resolved)));
} else {
gfx_rapi->resolve_msaa_color_buffer(0, game_framebuffer);
}
} else {
SohUtils::saveEnvironmentVar("framebuffer", std::to_string((uintptr_t)gfx_rapi->get_framebuffer_texture_id(game_framebuffer)));
}
}
SohImGui::DrawFramebufferAndGameInput();
SohImGui::Render();
double t1 = gfx_wapi->get_time(); double t1 = gfx_wapi->get_time();
//printf("Process %f %f\n", t1, t1 - t0); //printf("Process %f %f\n", t1, t1 - t0);
gfx_rapi->end_frame(); gfx_rapi->end_frame();
@ -2739,21 +2791,47 @@ void gfx_set_framedivisor(int divisor) {
int gfx_create_framebuffer(uint32_t width, uint32_t height) { int gfx_create_framebuffer(uint32_t width, uint32_t height) {
uint32_t orig_width = width, orig_height = height; uint32_t orig_width = width, orig_height = height;
gfx_adjust_width_height_for_scale(width, height); gfx_adjust_width_height_for_scale(width, height);
int fb = gfx_rapi->create_framebuffer(width, height); int fb = gfx_rapi->create_framebuffer();
gfx_rapi->update_framebuffer_parameters(fb, width, height, 1, true, true, true, true);
framebuffers[fb] = { orig_width, orig_height, width, height }; framebuffers[fb] = { orig_width, orig_height, width, height };
return fb; return fb;
} }
void gfx_set_framebuffer(int fb) void gfx_set_framebuffer(int fb, float noise_scale) {
{ gfx_rapi->start_draw_to_framebuffer(fb, noise_scale);
gfx_rapi->set_framebuffer(fb); gfx_rapi->clear_framebuffer();
} }
void gfx_reset_framebuffer() void gfx_reset_framebuffer() {
{ gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
gfx_rapi->reset_framebuffer(); }
static void adjust_pixel_depth_coordinates(float& x, float& y) {
x = x * RATIO_Y - (SCREEN_WIDTH * RATIO_Y - gfx_current_dimensions.width) / 2;
y *= RATIO_Y;
if (!game_renders_to_framebuffer || (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
x += gfx_current_game_window_viewport.x;
y += gfx_current_window_dimensions.height - (gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
}
}
void gfx_get_pixel_depth_prepare(float x, float y) {
adjust_pixel_depth_coordinates(x, y);
get_pixel_depth_pending.emplace(x, y);
} }
uint16_t gfx_get_pixel_depth(float x, float y) { uint16_t gfx_get_pixel_depth(float x, float y) {
return gfx_rapi->get_pixel_depth(x * RATIO_Y - (SCREEN_WIDTH * RATIO_Y - gfx_current_dimensions.width) / 2, y * RATIO_Y); adjust_pixel_depth_coordinates(x, y);
if (auto it = get_pixel_depth_cached.find(make_pair(x, y)); it != get_pixel_depth_cached.end()) {
return it->second;
}
get_pixel_depth_pending.emplace(x, y);
map<pair<float, float>, uint16_t> res = gfx_rapi->get_pixel_depth(game_renders_to_framebuffer ? game_framebuffer : 0, get_pixel_depth_pending);
get_pixel_depth_cached.merge(res);
get_pixel_depth_pending.clear();
return get_pixel_depth_cached.find(make_pair(x, y))->second;
} }

View File

@ -8,8 +8,11 @@
struct GfxRenderingAPI; struct GfxRenderingAPI;
struct GfxWindowManagerAPI; struct GfxWindowManagerAPI;
struct GfxDimensions struct XYWidthHeight {
{ int16_t x, y, width, height;
};
struct GfxDimensions {
uint32_t internal_mul; uint32_t internal_mul;
uint32_t width, height; uint32_t width, height;
float aspect_ratio; float aspect_ratio;
@ -50,7 +53,10 @@ struct TextureCacheValue {
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
extern struct GfxDimensions gfx_current_dimensions; extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
extern struct XYWidthHeight gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
extern uint32_t gfx_msaa_level;
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen); void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void); struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
@ -60,6 +66,7 @@ void gfx_end_frame(void);
void gfx_set_framedivisor(int); void gfx_set_framedivisor(int);
void gfx_texture_cache_clear(); void gfx_texture_cache_clear();
int gfx_create_framebuffer(uint32_t width, uint32_t height); int gfx_create_framebuffer(uint32_t width, uint32_t height);
void gfx_get_pixel_depth_prepare(float x, float y);
uint16_t gfx_get_pixel_depth(float x, float y); uint16_t gfx_get_pixel_depth(float x, float y);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -5,10 +5,18 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <map>
#include <set>
struct ShaderProgram; struct ShaderProgram;
struct GfxClipParameters {
bool z_is_from_0_to_1;
bool invert_y;
};
struct GfxRenderingAPI { struct GfxRenderingAPI {
bool (*z_is_from_0_to_1)(void); struct GfxClipParameters (*get_clip_parameters)(void);
void (*unload_shader)(struct ShaderProgram *old_prg); void (*unload_shader)(struct ShaderProgram *old_prg);
void (*load_shader)(struct ShaderProgram *new_prg); void (*load_shader)(struct ShaderProgram *new_prg);
struct ShaderProgram *(*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1); struct ShaderProgram *(*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1);
@ -19,7 +27,6 @@ struct GfxRenderingAPI {
void (*upload_texture)(const uint8_t *rgba32_buf, uint32_t width, uint32_t height); void (*upload_texture)(const uint8_t *rgba32_buf, uint32_t width, uint32_t height);
void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt); void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt);
void (*set_depth_test_and_mask)(bool depth_test, bool z_upd); void (*set_depth_test_and_mask)(bool depth_test, bool z_upd);
uint16_t (*get_pixel_depth)(float x, float y);
void (*set_zmode_decal)(bool zmode_decal); void (*set_zmode_decal)(bool zmode_decal);
void (*set_viewport)(int x, int y, int width, int height); void (*set_viewport)(int x, int y, int width, int height);
void (*set_scissor)(int x, int y, int width, int height); void (*set_scissor)(int x, int y, int width, int height);
@ -30,11 +37,14 @@ struct GfxRenderingAPI {
void (*start_frame)(void); void (*start_frame)(void);
void (*end_frame)(void); void (*end_frame)(void);
void (*finish_render)(void); void (*finish_render)(void);
int (*create_framebuffer)(uint32_t width, uint32_t height); int (*create_framebuffer)();
void (*resize_framebuffer)(int fb, uint32_t width, uint32_t height); void (*update_framebuffer_parameters)(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, bool opengl_invert_y, bool render_target, bool has_depth_buffer, bool can_extract_depth);
void (*set_framebuffer)(int fb); void (*start_draw_to_framebuffer)(int fb_id, float noise_scale);
void (*reset_framebuffer)(); void (*clear_framebuffer)(void);
void (*select_texture_fb)(int fbID); void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
std::map<std::pair<float, float>, uint16_t> (*get_pixel_depth)(int fb_id, const std::set<std::pair<float, float>>& coordinates);
void *(*get_framebuffer_texture_id)(int fb_id);
void (*select_texture_fb)(int fb_id);
void (*delete_texture)(uint32_t texID); void (*delete_texture)(uint32_t texID);
}; };

View File

@ -502,7 +502,6 @@ namespace ImGui
IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text
IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)
IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape
IMGUI_API void ImageRotated(ImTextureID tex_id, ImVec2 center, ImVec2 size, float angle);
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0));
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding
IMGUI_API bool Checkbox(const char* label, bool* v); IMGUI_API bool Checkbox(const char* label, bool* v);

View File

@ -1007,33 +1007,6 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
return held; return held;
} }
void ImGui::ImageRotated(ImTextureID tex_id, ImVec2 center, ImVec2 size, float angle) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImRect bb(window->DC.CursorPos + ImVec2(size.x / 2, size.y / 2), window->DC.CursorPos + size);
ImVec2 pos[4] =
{
center + bb.Min + ImVec2(-size.x * 0.5f, -size.y * 0.5f),
center + bb.Min + ImVec2(+size.x * 0.5f, -size.y * 0.5f),
center + bb.Min + ImVec2(+size.x * 0.5f, +size.y * 0.5f),
center + bb.Min + ImVec2(-size.x * 0.5f, +size.y * 0.5f)
};
ImVec2 uvs[4] =
{
ImVec2(0.0f, 1.0f),
ImVec2(1.0f, 1.0f),
ImVec2(1.0f, 0.0f),
ImVec2(0.0f, 0.0f)
};
draw_list->AddImageQuad(tex_id, pos[0], pos[1], pos[2], pos[3], uvs[0], uvs[1], uvs[2], uvs[3], IM_COL32_WHITE);
}
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();

View File

@ -123,14 +123,6 @@ namespace SohImGui {
} }
} }
bool UseInternalRes() {
switch (impl.backend) {
case Backend::SDL:
return true;
}
return false;
}
bool UseViewports() { bool UseViewports() {
switch (impl.backend) { switch (impl.backend) {
case Backend::DX11: case Backend::DX11:
@ -281,20 +273,16 @@ namespace SohImGui {
} }
} }
void Draw() { void DrawMainMenuAndCalculateGameSize() {
console->Update(); console->Update();
ImGuiBackendNewFrame(); ImGuiBackendNewFrame();
ImGuiWMNewFrame(); ImGuiWMNewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
const std::shared_ptr<Window> wnd = GlobalCtx2::GetInstance()->GetWindow(); const std::shared_ptr<Window> wnd = GlobalCtx2::GetInstance()->GetWindow();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground |
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize; ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize;
if (UseViewports()) {
window_flags |= ImGuiWindowFlags_NoBackground;
}
if (Game::Settings.debug.menu_bar) window_flags |= ImGuiWindowFlags_MenuBar; if (Game::Settings.debug.menu_bar) window_flags |= ImGuiWindowFlags_MenuBar;
const ImGuiViewport* viewport = ImGui::GetMainViewport(); const ImGuiViewport* viewport = ImGui::GetMainViewport();
@ -302,8 +290,12 @@ namespace SohImGui {
ImGui::SetNextWindowSize(ImVec2(wnd->GetCurrentWidth(), wnd->GetCurrentHeight())); ImGui::SetNextWindowSize(ImVec2(wnd->GetCurrentWidth(), wnd->GetCurrentHeight()));
ImGui::SetNextWindowViewport(viewport->ID); ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f);
ImGui::Begin("Main - Deck", nullptr, window_flags); ImGui::Begin("Main - Deck", nullptr, window_flags);
ImGui::PopStyleVar(); ImGui::PopStyleVar(3);
ImVec2 top_left_pos = ImGui::GetWindowPos();
const ImGuiID dockId = ImGui::GetID("main_dock"); const ImGuiID dockId = ImGui::GetID("main_dock");
@ -421,9 +413,7 @@ namespace SohImGui {
ImGui::Text("Graphics"); ImGui::Text("Graphics");
ImGui::Separator(); ImGui::Separator();
if (UseInternalRes()) { HOOK(ImGui::Checkbox("N64 Mode", &Game::Settings.debug.n64mode));
HOOK(ImGui::Checkbox("N64 Mode", &Game::Settings.debug.n64mode));
}
if (ImGui::Checkbox("Animated Link in Pause Menu", &Game::Settings.enhancements.animated_pause_menu)) { if (ImGui::Checkbox("Animated Link in Pause Menu", &Game::Settings.enhancements.animated_pause_menu)) {
CVar_SetS32("gPauseLiveLink", Game::Settings.enhancements.animated_pause_menu); CVar_SetS32("gPauseLiveLink", Game::Settings.enhancements.animated_pause_menu);
@ -441,10 +431,10 @@ namespace SohImGui {
if (ImGui::BeginMenu("Developer Tools")) { if (ImGui::BeginMenu("Developer Tools")) {
HOOK(ImGui::MenuItem("Stats", nullptr, &Game::Settings.debug.soh)); HOOK(ImGui::MenuItem("Stats", nullptr, &Game::Settings.debug.soh));
HOOK(ImGui::MenuItem("Console", nullptr, &console->opened)); HOOK(ImGui::MenuItem("Console", nullptr, &console->opened));
ImGui::Text("Debug"); ImGui::Text("Debug");
ImGui::Separator(); ImGui::Separator();
if (ImGui::Checkbox("Debug Mode", &Game::Settings.cheats.debug_mode)) { if (ImGui::Checkbox("Debug Mode", &Game::Settings.cheats.debug_mode)) {
CVar_SetS32("gDebugEnabled", Game::Settings.cheats.debug_mode); CVar_SetS32("gDebugEnabled", Game::Settings.cheats.debug_mode);
needs_save = true; needs_save = true;
@ -452,7 +442,12 @@ namespace SohImGui {
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("Graphics")) {
HOOK(ImGui::MenuItem("Anti-aliasing", nullptr, &Game::Settings.graphics.show));
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Cheats")) { if (ImGui::BeginMenu("Cheats")) {
if (ImGui::Checkbox("Infinite Money", &Game::Settings.cheats.infinite_money)) { if (ImGui::Checkbox("Infinite Money", &Game::Settings.cheats.infinite_money)) {
CVar_SetS32("gInfiniteMoney", Game::Settings.cheats.infinite_money); CVar_SetS32("gInfiniteMoney", Game::Settings.cheats.infinite_money);
@ -473,22 +468,22 @@ namespace SohImGui {
CVar_SetS32("gInfiniteMagic", Game::Settings.cheats.infinite_magic); CVar_SetS32("gInfiniteMagic", Game::Settings.cheats.infinite_magic);
needs_save = true; needs_save = true;
} }
if (ImGui::Checkbox("No Clip", &Game::Settings.cheats.no_clip)) { if (ImGui::Checkbox("No Clip", &Game::Settings.cheats.no_clip)) {
CVar_SetS32("gNoClip", Game::Settings.cheats.no_clip); CVar_SetS32("gNoClip", Game::Settings.cheats.no_clip);
needs_save = true; needs_save = true;
} }
if (ImGui::Checkbox("Climb Everything", &Game::Settings.cheats.climb_everything)) { if (ImGui::Checkbox("Climb Everything", &Game::Settings.cheats.climb_everything)) {
CVar_SetS32("gClimbEverything", Game::Settings.cheats.climb_everything); CVar_SetS32("gClimbEverything", Game::Settings.cheats.climb_everything);
needs_save = true; needs_save = true;
} }
if (ImGui::Checkbox("Moon Jump on L", &Game::Settings.cheats.moon_jump_on_l)) { if (ImGui::Checkbox("Moon Jump on L", &Game::Settings.cheats.moon_jump_on_l)) {
CVar_SetS32("gMoonJumpOnL", Game::Settings.cheats.moon_jump_on_l); CVar_SetS32("gMoonJumpOnL", Game::Settings.cheats.moon_jump_on_l);
needs_save = true; needs_save = true;
} }
if (ImGui::Checkbox("Super Tunic", &Game::Settings.cheats.super_tunic)) { if (ImGui::Checkbox("Super Tunic", &Game::Settings.cheats.super_tunic)) {
CVar_SetS32("gSuperTunic", Game::Settings.cheats.super_tunic); CVar_SetS32("gSuperTunic", Game::Settings.cheats.super_tunic);
needs_save = true; needs_save = true;
@ -509,36 +504,6 @@ namespace SohImGui {
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
ImGui::End();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
if (UseViewports()) {
flags |= ImGuiWindowFlags_NoBackground;
}
ImGui::Begin("OoT Master Quest", nullptr, flags);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImVec2 main_pos = ImGui::GetWindowPos();
ImVec2 size = ImGui::GetContentRegionAvail();
ImVec2 pos = ImVec2(0, 0);
gfx_current_dimensions.width = size.x * gfx_current_dimensions.internal_mul;
gfx_current_dimensions.height = size.y * gfx_current_dimensions.internal_mul;
if (UseInternalRes()) {
if (Game::Settings.debug.n64mode) {
gfx_current_dimensions.width = 320;
gfx_current_dimensions.height = 240;
const int sw = size.y * 320 / 240;
pos = ImVec2(size.x / 2 - sw / 2, 0);
size = ImVec2(sw, size.y);
}
}
if (UseInternalRes()) {
int fbuf = std::stoi(SohUtils::getEnvironmentVar("framebuffer"));
ImGui::ImageRotated(reinterpret_cast<ImTextureID>(fbuf), pos, size, 0.0f);
}
ImGui::End(); ImGui::End();
if (Game::Settings.debug.soh) { if (Game::Settings.debug.soh) {
@ -548,18 +513,84 @@ namespace SohImGui {
ImGui::Text("Platform: Windows"); ImGui::Text("Platform: Windows");
ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / framerate, framerate); ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / framerate, framerate);
if (UseInternalRes()) {
ImGui::Text("Internal Resolution:");
ImGui::SliderInt("Mul", reinterpret_cast<int*>(&gfx_current_dimensions.internal_mul), 1, 8);
}
ImGui::End(); ImGui::End();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
if (Game::Settings.graphics.show) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Anti-aliasing settings", nullptr, ImGuiWindowFlags_None);
ImGui::Text("Internal Resolution:");
ImGui::SliderInt("Mul", reinterpret_cast<int*>(&gfx_current_dimensions.internal_mul), 1, 8);
ImGui::Text("MSAA:");
ImGui::SliderInt("MSAA", reinterpret_cast<int*>(&gfx_msaa_level), 1, 8);
ImGui::End();
ImGui::PopStyleColor();
}
console->Draw();
for (auto& windowIter : customWindows) {
CustomWindow& window = windowIter.second;
if (window.drawFunc != nullptr) {
window.drawFunc(window.enabled);
}
}
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground;
ImGui::Begin("OoT Master Quest", nullptr, flags);
ImGui::PopStyleVar(3);
ImGui::PopStyleColor();
ImVec2 main_pos = ImGui::GetWindowPos();
main_pos.x -= top_left_pos.x;
main_pos.y -= top_left_pos.y;
ImVec2 size = ImGui::GetContentRegionAvail();
ImVec2 pos = ImVec2(0, 0);
gfx_current_dimensions.width = size.x * gfx_current_dimensions.internal_mul;
gfx_current_dimensions.height = size.y * gfx_current_dimensions.internal_mul;
gfx_current_game_window_viewport.x = main_pos.x;
gfx_current_game_window_viewport.y = main_pos.y;
gfx_current_game_window_viewport.width = size.x;
gfx_current_game_window_viewport.height = size.y;
if (Game::Settings.debug.n64mode) {
gfx_current_dimensions.width = 320;
gfx_current_dimensions.height = 240;
const int sw = size.y * 320 / 240;
gfx_current_game_window_viewport.x += (size.x - sw) / 2;
gfx_current_game_window_viewport.width = sw;
pos = ImVec2(size.x / 2 - sw / 2, 0);
size = ImVec2(sw, size.y);
}
}
void DrawFramebufferAndGameInput() {
ImVec2 main_pos = ImGui::GetWindowPos();
ImVec2 size = ImGui::GetContentRegionAvail();
ImVec2 pos = ImVec2(0, 0);
if (Game::Settings.debug.n64mode) {
const int sw = size.y * 320 / 240;
pos = ImVec2(size.x / 2 - sw / 2, 0);
size = ImVec2(sw, size.y);
}
std::string fb_str = SohUtils::getEnvironmentVar("framebuffer");
if (!fb_str.empty()) {
uintptr_t fbuf = (uintptr_t)std::stoull(fb_str);
//ImGui::ImageSimple(reinterpret_cast<ImTextureID>(fbuf), pos, size);
ImGui::SetCursorPos(pos);
ImGui::Image(reinterpret_cast<ImTextureID>(fbuf), size);
}
ImGui::End();
const float scale = Game::Settings.controller.input_scale; const float scale = Game::Settings.controller.input_scale;
ImVec2 BtnPos = ImVec2(160 * scale, 85 * scale); ImVec2 BtnPos = ImVec2(160 * scale, 85 * scale);
if(Game::Settings.controller.input_enabled) { if (Game::Settings.controller.input_enabled) {
ImGui::SetNextWindowSize(BtnPos); ImGui::SetNextWindowSize(BtnPos);
ImGui::SetNextWindowPos(ImVec2(main_pos.x + size.x - BtnPos.x - 20, main_pos.y + size.y - BtnPos.y - 20)); ImGui::SetNextWindowPos(ImVec2(main_pos.x + size.x - BtnPos.x - 20, main_pos.y + size.y - BtnPos.y - 20));
@ -605,16 +636,9 @@ namespace SohImGui {
ImGui::End(); ImGui::End();
} }
} }
}
console->Draw(); void Render() {
for (auto& windowIter : customWindows) {
CustomWindow& window = windowIter.second;
if (window.drawFunc != nullptr) {
window.drawFunc(window.enabled);
}
}
ImGui::Render(); ImGui::Render();
ImGuiRenderDrawData(ImGui::GetDrawData()); ImGuiRenderDrawData(ImGui::GetDrawData());
if (UseViewports()) { if (UseViewports()) {
@ -623,6 +647,13 @@ namespace SohImGui {
} }
} }
void CancelFrame() {
ImGui::EndFrame();
if (UseViewports()) {
ImGui::UpdatePlatformWindows();
}
}
void BindCmd(const std::string& cmd, CommandEntry entry) { void BindCmd(const std::string& cmd, CommandEntry entry) {
console->Commands[cmd] = std::move(entry); console->Commands[cmd] = std::move(entry);
} }

View File

@ -60,7 +60,10 @@ namespace SohImGui {
extern Console* console; extern Console* console;
void Init(WindowImpl window_impl); void Init(WindowImpl window_impl);
void Update(EventImpl event); void Update(EventImpl event);
void Draw(void); void DrawMainMenuAndCalculateGameSize(void);
void DrawFramebufferAndGameInput(void);
void Render(void);
void CancelFrame(void);
void ShowCursor(bool hide, Dialogues w); void ShowCursor(bool hide, Dialogues w);
void BindCmd(const std::string& cmd, CommandEntry entry); void BindCmd(const std::string& cmd, CommandEntry entry);
void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc); void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc);

View File

@ -286,6 +286,10 @@ namespace Ship {
//gfx_set_framedivisor(0); //gfx_set_framedivisor(0);
} }
void Window::GetPixelDepthPrepare(float x, float y) {
gfx_get_pixel_depth_prepare(x, y);
}
uint16_t Window::GetPixelDepth(float x, float y) { uint16_t Window::GetPixelDepth(float x, float y) {
return gfx_get_pixel_depth(x, y); return gfx_get_pixel_depth(x, y);
} }

View File

@ -20,6 +20,7 @@ namespace Ship {
void Init(); void Init();
void RunCommands(Gfx* Commands); void RunCommands(Gfx* Commands);
void SetFrameDivisor(int divisor); void SetFrameDivisor(int divisor);
void GetPixelDepthPrepare(float x, float y);
uint16_t GetPixelDepth(float x, float y); uint16_t GetPixelDepth(float x, float y);
void ToggleFullscreen(); void ToggleFullscreen();
void SetFullscreen(bool bIsFullscreen); void SetFullscreen(bool bIsFullscreen);

View File

@ -977,6 +977,7 @@ void LightContext_RemoveLight(GlobalContext* globalCtx, LightContext* lightCtx,
Lights* Lights_NewAndDraw(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambientB, u8 numLights, u8 r, u8 g, Lights* Lights_NewAndDraw(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambientB, u8 numLights, u8 r, u8 g,
u8 b, s8 x, s8 y, s8 z); u8 b, s8 x, s8 y, s8 z);
Lights* Lights_New(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambientB); Lights* Lights_New(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambientB);
void Lights_GlowCheckPrepare(GlobalContext* globalCtx);
void Lights_GlowCheck(GlobalContext* globalCtx); void Lights_GlowCheck(GlobalContext* globalCtx);
void Lights_DrawGlow(GlobalContext* globalCtx); void Lights_DrawGlow(GlobalContext* globalCtx);
void ZeldaArena_CheckPointer(void* ptr, size_t size, const char* name, const char* action); void ZeldaArena_CheckPointer(void* ptr, size_t size, const char* name, const char* action);

View File

@ -9,6 +9,7 @@ void Graph_ProcessGfxCommands(Gfx* commands);
void OTRLogString(const char* src); void OTRLogString(const char* src);
void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char)); void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char));
void OTRSetFrameDivisor(int divisor); void OTRSetFrameDivisor(int divisor);
void OTRGetPixelDepthPrepare(float x, float y);
uint16_t OTRGetPixelDepth(float x, float y); uint16_t OTRGetPixelDepth(float x, float y);
int32_t OTRGetLastScancode(); int32_t OTRGetLastScancode();
void ResourceMgr_CacheDirectory(const char* resName); void ResourceMgr_CacheDirectory(const char* resName);

View File

@ -24,9 +24,17 @@
#include "../soh/Enhancements/debugconsole.h" #include "../soh/Enhancements/debugconsole.h"
#include "../soh/Enhancements/debugger/debugger.h" #include "../soh/Enhancements/debugger/debugger.h"
#include "Utils/BitConverter.h" #include "Utils/BitConverter.h"
#include "variables.h"
OTRGlobals* OTRGlobals::Instance; OTRGlobals* OTRGlobals::Instance;
static struct {
std::condition_variable cv_to_thread, cv_from_thread;
std::mutex mutex;
bool initialized;
bool processing;
} audio;
OTRGlobals::OTRGlobals() { OTRGlobals::OTRGlobals() {
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian"); context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
context->GetWindow()->Init(); context->GetWindow()->Init();
@ -39,6 +47,10 @@ extern uintptr_t clearMtx;
extern "C" Mtx gMtxClear; extern "C" Mtx gMtxClear;
extern "C" MtxF gMtxFClear; extern "C" MtxF gMtxFClear;
extern "C" void OTRMessage_Init(); extern "C" void OTRMessage_Init();
extern "C" void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples);
extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len);
extern "C" int AudioPlayer_Buffered(void);
extern "C" int AudioPlayer_GetDesiredBuffered(void);
// C->C++ Bridge // C->C++ Bridge
extern "C" void InitOTR() { extern "C" void InitOTR() {
@ -80,8 +92,67 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) {
// C->C++ Bridge // C->C++ Bridge
extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(R_UPDATE_RATE);
if (!audio.initialized) {
audio.initialized = true;
std::thread([]() {
for (;;) {
{
std::unique_lock<std::mutex> Lock(audio.mutex);
while (!audio.processing) {
audio.cv_to_thread.wait(Lock);
}
}
//AudioMgr_ThreadEntry(&gAudioMgr);
// 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333..
// in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528
#define SAMPLES_HIGH 560
#define SAMPLES_LOW 528
// PAL values
//#define SAMPLES_HIGH 656
//#define SAMPLES_LOW 624
#define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 )
#define NUM_AUDIO_CHANNELS 2
int samples_left = AudioPlayer_Buffered();
u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW;
// printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
// 3 is the maximum authentic frame divisor.
s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3];
for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) {
AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples);
}
//for (uint32_t i = 0; i < 2 * num_audio_samples; i++) {
// audio_buffer[i] = Rand_Next() & 0xFF;
//}
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
{
std::unique_lock<std::mutex> Lock(audio.mutex);
audio.processing = false;
}
audio.cv_from_thread.notify_one();
}
}).detach();
}
{
std::unique_lock<std::mutex> Lock(audio.mutex);
audio.processing = true;
}
audio.cv_to_thread.notify_one();
OTRGlobals::Instance->context->GetWindow()->RunCommands(commands); OTRGlobals::Instance->context->GetWindow()->RunCommands(commands);
{
std::unique_lock<std::mutex> Lock(audio.mutex);
while (audio.processing) {
audio.cv_from_thread.wait(Lock);
}
}
// OTRTODO: FIGURE OUT END FRAME POINT // OTRTODO: FIGURE OUT END FRAME POINT
/* if (OTRGlobals::Instance->context->GetWindow()->lastScancode != -1) /* if (OTRGlobals::Instance->context->GetWindow()->lastScancode != -1)
OTRGlobals::Instance->context->GetWindow()->lastScancode = -1;*/ OTRGlobals::Instance->context->GetWindow()->lastScancode = -1;*/
@ -90,8 +161,8 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
float divisor_num = 0.0f; float divisor_num = 0.0f;
extern "C" void OTRSetFrameDivisor(int divisor) { extern "C" void OTRGetPixelDepthPrepare(float x, float y) {
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(divisor); OTRGlobals::Instance->context->GetWindow()->GetPixelDepthPrepare(x, y);
} }
extern "C" uint16_t OTRGetPixelDepth(float x, float y) { extern "C" uint16_t OTRGetPixelDepth(float x, float y) {

View File

@ -24,7 +24,7 @@ void Graph_ProcessFrame(void (*run_one_game_iter)(void));
void Graph_ProcessGfxCommands(Gfx* commands); void Graph_ProcessGfxCommands(Gfx* commands);
void OTRLogString(const char* src); void OTRLogString(const char* src);
void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char)); void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char));
void OTRSetFrameDivisor(int divisor); void OTRGetPixelDepthPrepare(float x, float y);
uint16_t OTRGetPixelDepth(float x, float y); uint16_t OTRGetPixelDepth(float x, float y);
int32_t OTRGetLastScancode(); int32_t OTRGetLastScancode();
uint32_t ResourceMgr_GetGameVersion(); uint32_t ResourceMgr_GetGameVersion();

View File

@ -468,35 +468,6 @@ static void RunFrame()
{ {
uint64_t ticksA, ticksB; uint64_t ticksA, ticksB;
ticksA = GetPerfCounter(); ticksA = GetPerfCounter();
OTRSetFrameDivisor(R_UPDATE_RATE);
//OTRSetFrameDivisor(0);
//AudioMgr_ThreadEntry(&gAudioMgr);
// 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333..
// in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528
#define SAMPLES_HIGH 560
#define SAMPLES_LOW 528
// PAL values
//#define SAMPLES_HIGH 656
//#define SAMPLES_LOW 624
#define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 )
#define NUM_AUDIO_CHANNELS 2
int samples_left = AudioPlayer_Buffered();
u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW;
// printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
// 3 is the maximum authentic frame divisor.
s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3];
for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) {
AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples);
}
//for (uint32_t i = 0; i < 2 * num_audio_samples; i++) {
// audio_buffer[i] = Rand_Next() & 0xFF;
//}
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
PadMgr_ThreadEntry(&gPadMgr); PadMgr_ThreadEntry(&gPadMgr);

View File

@ -226,6 +226,9 @@ u16 Environment_GetPixelDepth(s32 x, s32 y) {
void Environment_GraphCallback(GraphicsContext* gfxCtx, void* param) { void Environment_GraphCallback(GraphicsContext* gfxCtx, void* param) {
GlobalContext* globalCtx = (GlobalContext*)param; GlobalContext* globalCtx = (GlobalContext*)param;
OTRGetPixelDepthPrepare(D_8015FD7E, D_8015FD80);
Lights_GlowCheckPrepare(globalCtx);
D_8011FB44 = Environment_GetPixelDepth(D_8015FD7E, D_8015FD80); D_8011FB44 = Environment_GetPixelDepth(D_8015FD7E, D_8015FD80);
Lights_GlowCheck(globalCtx); Lights_GlowCheck(globalCtx);
} }

View File

@ -323,6 +323,44 @@ Lights* Lights_New(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambient
return lights; return lights;
} }
void Lights_GlowCheckPrepare(GlobalContext* globalCtx) {
LightNode* node;
LightPoint* params;
Vec3f pos;
Vec3f multDest;
f32 wDest;
f32 wX;
f32 wY;
node = globalCtx->lightCtx.listHead;
while (node != NULL) {
params = &node->info->params.point;
if (node->info->type == LIGHT_POINT_GLOW) {
f32 x, y;
u32 shrink;
uint32_t height;
pos.x = params->x;
pos.y = params->y;
pos.z = params->z;
func_8002BE04(globalCtx, &pos, &multDest, &wDest);
wX = multDest.x * wDest;
wY = multDest.y * wDest;
x = wX * 160 + 160;
y = wY * 120 + 120;
shrink = ShrinkWindow_GetCurrentVal();
if ((multDest.z > 1.0f) && y >= shrink && y <= SCREEN_HEIGHT - shrink) {
OTRGetPixelDepthPrepare(x, y);
}
}
node = node->next;
}
}
void Lights_GlowCheck(GlobalContext* globalCtx) { void Lights_GlowCheck(GlobalContext* globalCtx) {
LightNode* node; LightNode* node;
LightPoint* params; LightPoint* params;