mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-25 10:52:19 -05:00
Graphics backend enhancements etc. (#163)
This commit is contained in:
parent
fe6dbd2a5b
commit
ceef4a9453
@ -52,6 +52,11 @@ struct SoHConfigType {
|
||||
bool moon_jump_on_l = false;
|
||||
bool super_tunic = false;
|
||||
} cheats;
|
||||
|
||||
// Graphics
|
||||
struct {
|
||||
bool show = false;
|
||||
} graphics;
|
||||
};
|
||||
|
||||
enum SeqPlayers {
|
||||
|
@ -37,9 +37,8 @@ namespace {
|
||||
|
||||
struct PerFrameCB {
|
||||
uint32_t noise_frame;
|
||||
float noise_scale_x;
|
||||
float noise_scale_y;
|
||||
uint32_t padding;
|
||||
float noise_scale;
|
||||
uint32_t padding[2]; // constant buffers must be multiples of 16 bytes in size
|
||||
};
|
||||
|
||||
struct PerDrawCB {
|
||||
@ -51,12 +50,12 @@ struct PerDrawCB {
|
||||
} textures[2];
|
||||
};
|
||||
|
||||
struct CoordCB {
|
||||
float x, y;
|
||||
float padding[2]; // structure size must be multiple of 16
|
||||
struct Coord {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
struct TextureData {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11ShaderResourceView> resource_view;
|
||||
ComPtr<ID3D11SamplerState> sampler_state;
|
||||
uint32_t width;
|
||||
@ -64,10 +63,13 @@ struct TextureData {
|
||||
bool linear_filtering;
|
||||
};
|
||||
|
||||
struct FramebufferData {
|
||||
struct Framebuffer {
|
||||
ComPtr<ID3D11RenderTargetView> render_target_view;
|
||||
ComPtr<ID3D11DepthStencilView> depth_stencil_view;
|
||||
ComPtr<ID3D11ShaderResourceView> depth_stencil_srv;
|
||||
uint32_t texture_id;
|
||||
bool has_depth_buffer;
|
||||
uint32_t msaa_level;
|
||||
};
|
||||
|
||||
struct ShaderProgramD3D11 {
|
||||
@ -91,34 +93,30 @@ static struct {
|
||||
pD3DCompile D3DCompile;
|
||||
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
uint32_t msaa_num_quality_levels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT];
|
||||
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
ComPtr<ID3D11RenderTargetView> backbuffer_view;
|
||||
ComPtr<ID3D11DepthStencilView> depth_stencil_view;
|
||||
ComPtr<ID3D11ShaderResourceView> depth_stencil_srv;
|
||||
ComPtr<ID3D11RasterizerState> rasterizer_state;
|
||||
ComPtr<ID3D11DepthStencilState> depth_stencil_state;
|
||||
ComPtr<ID3D11Buffer> vertex_buffer;
|
||||
ComPtr<ID3D11Buffer> per_frame_cb;
|
||||
ComPtr<ID3D11Buffer> per_draw_cb;
|
||||
ComPtr<ID3D11Texture2D> depth_stencil_texture;
|
||||
ComPtr<ID3D11Texture2D> depth_stencil_copy_texture;
|
||||
ComPtr<ID3D11Buffer> coord_buffer;
|
||||
ComPtr<ID3D11ShaderResourceView> coord_buffer_srv;
|
||||
ComPtr<ID3D11Buffer> depth_value_output_buffer;
|
||||
ComPtr<ID3D11Buffer> depth_value_output_buffer_copy;
|
||||
ComPtr<ID3D11UnorderedAccessView> depth_value_output_uav;
|
||||
ComPtr<ID3D11SamplerState> depth_value_sampler;
|
||||
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
|
||||
ComPtr<ID3D11Debug> debug;
|
||||
#endif
|
||||
|
||||
DXGI_SAMPLE_DESC sample_description;
|
||||
|
||||
PerFrameCB per_frame_cb_data;
|
||||
PerDrawCB per_draw_cb_data;
|
||||
|
||||
@ -128,14 +126,15 @@ static struct {
|
||||
int current_tile;
|
||||
uint32_t current_texture_ids[2];
|
||||
|
||||
std::vector<FramebufferData> framebuffers;
|
||||
std::vector<Framebuffer> framebuffers;
|
||||
|
||||
// Current state
|
||||
|
||||
struct ShaderProgramD3D11 *shader_program;
|
||||
|
||||
uint32_t current_width, current_height;
|
||||
//uint32_t current_width, current_height;
|
||||
uint32_t render_target_height;
|
||||
int current_framebuffer;
|
||||
|
||||
int8_t depth_test;
|
||||
int8_t depth_mask;
|
||||
@ -156,7 +155,9 @@ static struct {
|
||||
|
||||
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;
|
||||
texture_desc.Width = width;
|
||||
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.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
|
||||
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.Usage = D3D11_USAGE_DEFAULT;
|
||||
texture_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | (srv != nullptr ? D3D11_BIND_SHADER_RESOURCE : 0);
|
||||
texture_desc.CPUAccessFlags = 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;
|
||||
view_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
|
||||
DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
view_desc.Flags = 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) {
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
srv_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
|
||||
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.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) {
|
||||
// Load 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
|
||||
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.");
|
||||
#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
|
||||
|
||||
@ -364,61 +319,30 @@ static void gfx_d3d11_init(void) {
|
||||
|
||||
// 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"(
|
||||
sampler my_sampler : register(s0);
|
||||
Texture2D<float> tex : register(t0);
|
||||
cbuffer coordCB : register(b0) {
|
||||
float2 coord;
|
||||
}
|
||||
|
||||
StructuredBuffer<int2> coord : register(t1);
|
||||
RWStructuredBuffer<float> output : register(u0);
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
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
|
||||
UINT compile_flags = D3DCOMPILE_DEBUG;
|
||||
#else
|
||||
@ -426,7 +350,9 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
|
||||
#endif
|
||||
|
||||
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)) {
|
||||
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()));
|
||||
|
||||
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
|
||||
|
||||
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) {
|
||||
return true;
|
||||
static struct GfxClipParameters gfx_d3d11_get_clip_parameters(void) {
|
||||
return { true, false };
|
||||
}
|
||||
|
||||
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].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
|
||||
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].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
} 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) {
|
||||
// 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;
|
||||
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.SysMemSlicePitch = resource_data.SysMemPitch * height;
|
||||
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
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;
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, &resource_data, texture_data->texture.ReleaseAndGetAddressOf()));
|
||||
|
||||
// Create shader resource view from texture
|
||||
|
||||
if (texture_data->resource_view.Get() != nullptr) {
|
||||
// Free the previous texture in this slot
|
||||
texture_data->resource_view.Reset();
|
||||
}
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), nullptr, texture_data->resource_view.GetAddressOf()));
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture_data->texture.Get(), nullptr, texture_data->resource_view.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
|
||||
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) {
|
||||
create_render_target_views(true);
|
||||
//create_render_target_views(true);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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) {
|
||||
SohImGui::Draw();
|
||||
d3d.context->Flush();
|
||||
}
|
||||
|
||||
@ -847,43 +752,13 @@ static void gfx_d3d11_finish_render(void) {
|
||||
d3d.context->Flush();
|
||||
}
|
||||
|
||||
void gfx_d3d11_resize_framebuffer(int fb, uint32_t width, uint32_t height) {
|
||||
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) {
|
||||
int gfx_d3d11_create_framebuffer(void) {
|
||||
uint32_t texture_id = gfx_d3d11_new_texture();
|
||||
TextureData& t = d3d.textures[texture_id];
|
||||
t.width = width;
|
||||
t.height = height;
|
||||
|
||||
size_t index = d3d.framebuffers.size();
|
||||
d3d.framebuffers.resize(d3d.framebuffers.size() + 1);
|
||||
FramebufferData& data = d3d.framebuffers.back();
|
||||
Framebuffer& data = d3d.framebuffers.back();
|
||||
data.texture_id = texture_id;
|
||||
|
||||
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);
|
||||
d3d.current_texture_ids[tile] = saved;
|
||||
|
||||
gfx_d3d11_resize_framebuffer(index, width, height);
|
||||
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
void gfx_d3d11_set_framebuffer(int fb) {
|
||||
d3d.render_target_height = d3d.textures[d3d.framebuffers[fb].texture_id].height;
|
||||
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) {
|
||||
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 };
|
||||
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);
|
||||
bool diff = tex.width != width || tex.height != height || fb.msaa_level != msaa_level;
|
||||
|
||||
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) {
|
||||
d3d.render_target_height = d3d.current_height;
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
|
||||
void gfx_d3d11_start_draw_to_framebuffer(int fb_id, float noise_scale) {
|
||||
Framebuffer& fb = d3d.framebuffers[fb_id];
|
||||
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) {
|
||||
@ -917,62 +877,107 @@ void gfx_d3d11_select_texture_fb(int fbID) {
|
||||
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;
|
||||
|
||||
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
|
||||
d3d.context->CSSetShader(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->CSSetShader(fb.msaa_level > 1 ? d3d.compute_shader_msaa.Get() : d3d.compute_shader.Get(), nullptr, 0);
|
||||
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));
|
||||
CoordCB* coord_cb = (CoordCB*)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
|
||||
coord_cb->y = 1 - y / d3d.current_height;
|
||||
Coord *coord_cb = (Coord *)ms.pData;
|
||||
{
|
||||
size_t i = 0;
|
||||
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);
|
||||
|
||||
// The depth stencil texture can only have one mapping at a time, so temporarily unbind from the OM
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), nullptr);
|
||||
d3d.context->CSSetShaderResources(0, 1, d3d.depth_stencil_srv.GetAddressOf());
|
||||
// The depth stencil texture can only have one mapping at a time, so unbind from the OM
|
||||
ID3D11RenderTargetView* null_arr1[1] = { nullptr };
|
||||
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());
|
||||
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;
|
||||
{
|
||||
size_t i = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
res.emplace(coord, ((float *)ms.pData)[i++] * 65532.0f);
|
||||
}
|
||||
}
|
||||
d3d.context->Unmap(d3d.depth_value_output_buffer_copy.Get(), 0);
|
||||
|
||||
ID3D11ShaderResourceView *null_arr[1] = { nullptr };
|
||||
d3d.context->CSSetShaderResources(0, 1, null_arr);
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
|
||||
ID3D11ShaderResourceView *null_arr[2] = { nullptr, nullptr };
|
||||
d3d.context->CSSetShaderResources(0, 2, null_arr);
|
||||
|
||||
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);
|
||||
return res * 65532.0f;
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -982,7 +987,7 @@ ImTextureID SohImGui::GetTextureByID(int id) {
|
||||
}
|
||||
|
||||
struct GfxRenderingAPI gfx_direct3d11_api = {
|
||||
gfx_d3d11_z_is_from_0_to_1,
|
||||
gfx_d3d11_get_clip_parameters,
|
||||
gfx_d3d11_unload_shader,
|
||||
gfx_d3d11_load_shader,
|
||||
gfx_d3d11_create_and_load_new_shader,
|
||||
@ -993,7 +998,6 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
|
||||
gfx_d3d11_upload_texture,
|
||||
gfx_d3d11_set_sampler_parameters,
|
||||
gfx_d3d11_set_depth_test_and_mask,
|
||||
gfx_d3d11_get_pixel_depth,
|
||||
gfx_d3d11_set_zmode_decal,
|
||||
gfx_d3d11_set_viewport,
|
||||
gfx_d3d11_set_scissor,
|
||||
@ -1005,9 +1009,12 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
|
||||
gfx_d3d11_end_frame,
|
||||
gfx_d3d11_finish_render,
|
||||
gfx_d3d11_create_framebuffer,
|
||||
gfx_d3d11_resize_framebuffer,
|
||||
gfx_d3d11_set_framebuffer,
|
||||
gfx_d3d11_reset_framebuffer,
|
||||
gfx_d3d11_update_framebuffer_parameters,
|
||||
gfx_d3d11_start_draw_to_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_delete_texture
|
||||
};
|
||||
|
@ -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) {
|
||||
append_line(buf, &len, " float4 fog : FOG;");
|
||||
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) {
|
||||
append_line(buf, &len, "cbuffer PerFrameCB : register(b0) {");
|
||||
append_line(buf, &len, " uint noise_frame;");
|
||||
append_line(buf, &len, " float2 noise_scale;");
|
||||
append_line(buf, &len, " float noise_scale;");
|
||||
append_line(buf, &len, "}");
|
||||
|
||||
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, " PSInput result;");
|
||||
append_line(buf, &len, " result.position = position;");
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(buf, &len, " result.screenPos = position;");
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[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) {
|
||||
append_line(buf, &len, "[RootSignature(RS)]");
|
||||
}
|
||||
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++) {
|
||||
if (cc_features.used_textures[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) {
|
||||
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));");
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <windows.h>
|
||||
#include <wrl/client.h>
|
||||
#include <dxgi1_3.h>
|
||||
#include <dxgi1_4.h>
|
||||
#include <versionhelpers.h>
|
||||
|
||||
#include <shellscalingapi.h>
|
||||
@ -61,6 +62,7 @@ static struct {
|
||||
RECT last_window_rect;
|
||||
bool is_full_screen, last_maximized_state;
|
||||
|
||||
bool dxgi1_4;
|
||||
ComPtr<IDXGIFactory2> factory;
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
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) {
|
||||
int key = ((l_param >> 16) & 0x1ff);
|
||||
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);
|
||||
switch (message) {
|
||||
case WM_SIZE:
|
||||
gfx_dxgi_on_resize();
|
||||
dxgi.current_width = (uint32_t)(l_param & 0xffff);
|
||||
dxgi.current_height = (uint32_t)(l_param >> 16);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
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));
|
||||
}
|
||||
|
||||
{
|
||||
ComPtr<IDXGIFactory4> factory4;
|
||||
if (dxgi.factory->QueryInterface(__uuidof(IDXGIFactory4), &factory4) == S_OK) {
|
||||
dxgi.dxgi1_4 = true;
|
||||
}
|
||||
}
|
||||
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (UINT i = 0; dxgi.factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) {
|
||||
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.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swap_chain_desc.Scaling = win8 ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
|
||||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // Apparently this was backported to Win 7 Platform Update
|
||||
swap_chain_desc.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.SampleDesc.Count = 1;
|
||||
|
||||
|
@ -52,19 +52,33 @@ struct ShaderProgram {
|
||||
uint8_t num_attribs;
|
||||
bool used_noise;
|
||||
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 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 gfx_opengl_z_is_from_0_to_1(void) {
|
||||
return false;
|
||||
static uint32_t frame_count;
|
||||
|
||||
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) {
|
||||
@ -81,7 +95,7 @@ static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
|
||||
static void gfx_opengl_set_uniforms(struct ShaderProgram *prg) {
|
||||
if (prg->used_noise) {
|
||||
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) {
|
||||
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 = 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) {
|
||||
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) {
|
||||
@ -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) {
|
||||
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;
|
||||
} else {
|
||||
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) {
|
||||
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) {
|
||||
@ -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) {
|
||||
glViewport(x, y, width, height);
|
||||
current_height = 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);
|
||||
}
|
||||
|
||||
static unsigned int framebuffer;
|
||||
static unsigned int textureColorbuffer;
|
||||
static unsigned int rbo;
|
||||
|
||||
static void gfx_opengl_init(void) {
|
||||
//#if FOR_WINDOWS
|
||||
glewInit();
|
||||
@ -576,143 +585,214 @@ static void gfx_opengl_init(void) {
|
||||
glGenBuffers(1, &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);
|
||||
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_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++;
|
||||
|
||||
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) {
|
||||
|
||||
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);
|
||||
glFlush();
|
||||
}
|
||||
|
||||
static void gfx_opengl_finish_render(void) {
|
||||
}
|
||||
|
||||
static int gfx_opengl_create_framebuffer(uint32_t width, uint32_t height) {
|
||||
GLuint textureColorbuffer;
|
||||
|
||||
glGenTextures(1, &textureColorbuffer);
|
||||
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
static int gfx_opengl_create_framebuffer() {
|
||||
GLuint clrbuf;
|
||||
glGenTextures(1, &clrbuf);
|
||||
glBindTexture(GL_TEXTURE_2D, clrbuf);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 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);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
GLuint clrbuf_msaa;
|
||||
glGenRenderbuffers(1, &clrbuf_msaa);
|
||||
|
||||
GLuint rbo;
|
||||
glGenRenderbuffers(1, &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);
|
||||
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
size_t i = framebuffers.size();
|
||||
framebuffers.resize(i + 1);
|
||||
|
||||
fb2tex[fbo] = make_pair(textureColorbuffer, rbo);
|
||||
|
||||
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
framebuffers[i].fbo = fbo;
|
||||
framebuffers[i].clrbuf = clrbuf;
|
||||
framebuffers[i].clrbuf_msaa = clrbuf_msaa;
|
||||
framebuffers[i].rbo = rbo;
|
||||
|
||||
return fbo;
|
||||
}
|
||||
|
||||
static void gfx_opengl_resize_framebuffer(int fb, uint32_t width, uint32_t height) {
|
||||
glBindTexture(GL_TEXTURE_2D, fb2tex[fb].first);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
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) {
|
||||
Framebuffer& fb = framebuffers[fb_id];
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb2tex[fb].second);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
width = max(width, 1U);
|
||||
height = max(height, 1U);
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
void gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) {
|
||||
Framebuffer& fb = framebuffers[fb_id];
|
||||
|
||||
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);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void gfx_opengl_reset_framebuffer(void)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
|
||||
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) {
|
||||
glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
|
||||
}
|
||||
void gfx_opengl_resolve_msaa_color_buffer(int fb_id_target, int fb_id_source) {
|
||||
Framebuffer& fb_dst = framebuffers[fb_id_target];
|
||||
Framebuffer& fb_src = framebuffers[fb_id_source];
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_dst.fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_src.fbo);
|
||||
glBlitFramebuffer(0, 0, fb_src.width, fb_src.height, 0, 0, fb_dst.width, fb_dst.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
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);
|
||||
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) {
|
||||
float depth;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return depth * 65532.0f;
|
||||
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) {
|
||||
std::map<std::pair<float, float>, uint16_t> res;
|
||||
|
||||
Framebuffer& fb = framebuffers[fb_id];
|
||||
|
||||
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 = {
|
||||
gfx_opengl_z_is_from_0_to_1,
|
||||
gfx_opengl_get_clip_parameters,
|
||||
gfx_opengl_unload_shader,
|
||||
gfx_opengl_load_shader,
|
||||
gfx_opengl_create_and_load_new_shader,
|
||||
@ -723,7 +803,6 @@ struct GfxRenderingAPI gfx_opengl_api = {
|
||||
gfx_opengl_upload_texture,
|
||||
gfx_opengl_set_sampler_parameters,
|
||||
gfx_opengl_set_depth_test_and_mask,
|
||||
gfx_opengl_get_pixel_depth,
|
||||
gfx_opengl_set_zmode_decal,
|
||||
gfx_opengl_set_viewport,
|
||||
gfx_opengl_set_scissor,
|
||||
@ -735,9 +814,12 @@ struct GfxRenderingAPI gfx_opengl_api = {
|
||||
gfx_opengl_end_frame,
|
||||
gfx_opengl_finish_render,
|
||||
gfx_opengl_create_framebuffer,
|
||||
gfx_opengl_resize_framebuffer,
|
||||
gfx_opengl_set_framebuffer,
|
||||
gfx_opengl_reset_framebuffer,
|
||||
gfx_opengl_update_framebuffer_parameters,
|
||||
gfx_opengl_start_draw_to_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_delete_texture
|
||||
};
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@ -27,6 +28,8 @@
|
||||
|
||||
#include "../../luslog.h"
|
||||
#include "../StrHash64.h"
|
||||
#include "../../SohImGuiImpl.h"
|
||||
#include "../../Environment.h"
|
||||
|
||||
// OTRTODO: fix header files for these
|
||||
extern "C" {
|
||||
@ -71,10 +74,6 @@ struct RGBA {
|
||||
uint8_t r, g, b, a;
|
||||
};
|
||||
|
||||
struct XYWidthHeight {
|
||||
uint16_t x, y, width, height;
|
||||
};
|
||||
|
||||
struct LoadedVertex {
|
||||
float x, y, z, w;
|
||||
float u, v;
|
||||
@ -174,8 +173,16 @@ static struct RenderingState {
|
||||
TextureCacheNode *textures[2];
|
||||
} rendering_state;
|
||||
|
||||
struct GfxDimensions gfx_current_window_dimensions;
|
||||
struct GfxDimensions gfx_current_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;
|
||||
|
||||
@ -198,6 +205,9 @@ static bool fbActive = 0;
|
||||
static map<int, FBInfo>::iterator active_fb;
|
||||
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
|
||||
// TODO: Properly implement for MSVC
|
||||
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);
|
||||
|
||||
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++) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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]->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++] = w;
|
||||
|
||||
@ -1491,6 +1501,27 @@ static void gfx_sp_geometry_mode(uint32_t clear, uint32_t 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) {
|
||||
// 2 bits fraction
|
||||
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 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.y = y;
|
||||
rdp.viewport.width = width;
|
||||
rdp.viewport.height = height;
|
||||
|
||||
gfx_adjust_viewport_or_scissor(&rdp.viewport);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (tile > 8)
|
||||
{
|
||||
int bp = 0;
|
||||
}
|
||||
|
||||
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 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.y = y;
|
||||
rdp.scissor.width = width;
|
||||
rdp.scissor.height = height;
|
||||
|
||||
gfx_adjust_viewport_or_scissor(&rdp.scissor);
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
uint32_t geometry_mode_saved = rsp.geometry_mode;
|
||||
|
||||
gfx_adjust_viewport_or_scissor(&default_viewport);
|
||||
|
||||
rdp.viewport = default_viewport;
|
||||
rdp.viewport_or_scissor_changed = true;
|
||||
rsp.geometry_mode = 0;
|
||||
@ -2456,14 +2460,15 @@ static void gfx_run_dl(Gfx* cmd) {
|
||||
gfx_flush();
|
||||
fbActive = 1;
|
||||
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;
|
||||
case G_RESETFB:
|
||||
{
|
||||
gfx_flush();
|
||||
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;
|
||||
@ -2630,9 +2635,12 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co
|
||||
gfx_rapi = rapi;
|
||||
gfx_wapi->init(game_name, start_in_fullscreen);
|
||||
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.width = SCREEN_WIDTH;
|
||||
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++)
|
||||
segmentPointers[i] = NULL;
|
||||
@ -2681,7 +2689,8 @@ struct GfxRenderingAPI *gfx_get_current_rendering_api(void) {
|
||||
|
||||
void gfx_start_frame(void) {
|
||||
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) {
|
||||
// Avoid division by zero
|
||||
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;
|
||||
gfx_adjust_width_height_for_scale(width, 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_height = height;
|
||||
}
|
||||
@ -2701,6 +2710,22 @@ void gfx_start_frame(void) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2708,17 +2733,44 @@ void gfx_run(Gfx *commands) {
|
||||
gfx_sp_reset();
|
||||
|
||||
//puts("New frame");
|
||||
get_pixel_depth_pending.clear();
|
||||
get_pixel_depth_cached.clear();
|
||||
|
||||
if (!gfx_wapi->start_frame()) {
|
||||
dropped_frame = true;
|
||||
SohImGui::DrawFramebufferAndGameInput();
|
||||
SohImGui::CancelFrame();
|
||||
return;
|
||||
}
|
||||
dropped_frame = false;
|
||||
|
||||
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_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_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();
|
||||
//printf("Process %f %f\n", t1, t1 - t0);
|
||||
gfx_rapi->end_frame();
|
||||
@ -2739,21 +2791,47 @@ void gfx_set_framedivisor(int divisor) {
|
||||
int gfx_create_framebuffer(uint32_t width, uint32_t height) {
|
||||
uint32_t orig_width = width, orig_height = 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 };
|
||||
return fb;
|
||||
}
|
||||
|
||||
void gfx_set_framebuffer(int fb)
|
||||
{
|
||||
gfx_rapi->set_framebuffer(fb);
|
||||
void gfx_set_framebuffer(int fb, float noise_scale) {
|
||||
gfx_rapi->start_draw_to_framebuffer(fb, noise_scale);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
}
|
||||
|
||||
void gfx_reset_framebuffer()
|
||||
{
|
||||
gfx_rapi->reset_framebuffer();
|
||||
void gfx_reset_framebuffer() {
|
||||
gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
@ -8,8 +8,11 @@
|
||||
struct GfxRenderingAPI;
|
||||
struct GfxWindowManagerAPI;
|
||||
|
||||
struct GfxDimensions
|
||||
{
|
||||
struct XYWidthHeight {
|
||||
int16_t x, y, width, height;
|
||||
};
|
||||
|
||||
struct GfxDimensions {
|
||||
uint32_t internal_mul;
|
||||
uint32_t width, height;
|
||||
float aspect_ratio;
|
||||
@ -50,7 +53,10 @@ struct TextureCacheValue {
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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);
|
||||
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
|
||||
@ -60,6 +66,7 @@ void gfx_end_frame(void);
|
||||
void gfx_set_framedivisor(int);
|
||||
void gfx_texture_cache_clear();
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -5,10 +5,18 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
struct ShaderProgram;
|
||||
|
||||
struct GfxClipParameters {
|
||||
bool z_is_from_0_to_1;
|
||||
bool invert_y;
|
||||
};
|
||||
|
||||
struct GfxRenderingAPI {
|
||||
bool (*z_is_from_0_to_1)(void);
|
||||
struct GfxClipParameters (*get_clip_parameters)(void);
|
||||
void (*unload_shader)(struct ShaderProgram *old_prg);
|
||||
void (*load_shader)(struct ShaderProgram *new_prg);
|
||||
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 (*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);
|
||||
uint16_t (*get_pixel_depth)(float x, float y);
|
||||
void (*set_zmode_decal)(bool zmode_decal);
|
||||
void (*set_viewport)(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 (*end_frame)(void);
|
||||
void (*finish_render)(void);
|
||||
int (*create_framebuffer)(uint32_t width, uint32_t height);
|
||||
void (*resize_framebuffer)(int fb, uint32_t width, uint32_t height);
|
||||
void (*set_framebuffer)(int fb);
|
||||
void (*reset_framebuffer)();
|
||||
void (*select_texture_fb)(int fbID);
|
||||
int (*create_framebuffer)();
|
||||
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 (*start_draw_to_framebuffer)(int fb_id, float noise_scale);
|
||||
void (*clear_framebuffer)(void);
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -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 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 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 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);
|
||||
|
@ -1007,33 +1007,6 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
||||
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)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
@ -123,14 +123,6 @@ namespace SohImGui {
|
||||
}
|
||||
}
|
||||
|
||||
bool UseInternalRes() {
|
||||
switch (impl.backend) {
|
||||
case Backend::SDL:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UseViewports() {
|
||||
switch (impl.backend) {
|
||||
case Backend::DX11:
|
||||
@ -281,20 +273,16 @@ namespace SohImGui {
|
||||
}
|
||||
}
|
||||
|
||||
void Draw() {
|
||||
|
||||
void DrawMainMenuAndCalculateGameSize() {
|
||||
console->Update();
|
||||
ImGuiBackendNewFrame();
|
||||
ImGuiWMNewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
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_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoResize;
|
||||
if (UseViewports()) {
|
||||
window_flags |= ImGuiWindowFlags_NoBackground;
|
||||
}
|
||||
if (Game::Settings.debug.menu_bar) window_flags |= ImGuiWindowFlags_MenuBar;
|
||||
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
@ -302,8 +290,12 @@ namespace SohImGui {
|
||||
ImGui::SetNextWindowSize(ImVec2(wnd->GetCurrentWidth(), wnd->GetCurrentHeight()));
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
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::PopStyleVar();
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
ImVec2 top_left_pos = ImGui::GetWindowPos();
|
||||
|
||||
const ImGuiID dockId = ImGui::GetID("main_dock");
|
||||
|
||||
@ -421,9 +413,7 @@ namespace SohImGui {
|
||||
ImGui::Text("Graphics");
|
||||
ImGui::Separator();
|
||||
|
||||
if (UseInternalRes()) {
|
||||
HOOK(ImGui::Checkbox("N64 Mode", &Game::Settings.debug.n64mode));
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Animated Link in Pause Menu", &Game::Settings.enhancements.animated_pause_menu)) {
|
||||
CVar_SetS32("gPauseLiveLink", Game::Settings.enhancements.animated_pause_menu);
|
||||
@ -453,6 +443,11 @@ namespace SohImGui {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
HOOK(ImGui::MenuItem("Anti-aliasing", nullptr, &Game::Settings.graphics.show));
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Cheats")) {
|
||||
if (ImGui::Checkbox("Infinite Money", &Game::Settings.cheats.infinite_money)) {
|
||||
CVar_SetS32("gInfiniteMoney", Game::Settings.cheats.infinite_money);
|
||||
@ -509,36 +504,6 @@ namespace SohImGui {
|
||||
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();
|
||||
|
||||
if (Game::Settings.debug.soh) {
|
||||
@ -548,18 +513,84 @@ namespace SohImGui {
|
||||
|
||||
ImGui::Text("Platform: Windows");
|
||||
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::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;
|
||||
ImVec2 BtnPos = ImVec2(160 * scale, 85 * scale);
|
||||
|
||||
if(Game::Settings.controller.input_enabled) {
|
||||
if (Game::Settings.controller.input_enabled) {
|
||||
ImGui::SetNextWindowSize(BtnPos);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
console->Draw();
|
||||
|
||||
for (auto& windowIter : customWindows) {
|
||||
CustomWindow& window = windowIter.second;
|
||||
if (window.drawFunc != nullptr) {
|
||||
window.drawFunc(window.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void Render() {
|
||||
ImGui::Render();
|
||||
ImGuiRenderDrawData(ImGui::GetDrawData());
|
||||
if (UseViewports()) {
|
||||
@ -623,6 +647,13 @@ namespace SohImGui {
|
||||
}
|
||||
}
|
||||
|
||||
void CancelFrame() {
|
||||
ImGui::EndFrame();
|
||||
if (UseViewports()) {
|
||||
ImGui::UpdatePlatformWindows();
|
||||
}
|
||||
}
|
||||
|
||||
void BindCmd(const std::string& cmd, CommandEntry entry) {
|
||||
console->Commands[cmd] = std::move(entry);
|
||||
}
|
||||
|
@ -60,7 +60,10 @@ namespace SohImGui {
|
||||
extern Console* console;
|
||||
void Init(WindowImpl window_impl);
|
||||
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 BindCmd(const std::string& cmd, CommandEntry entry);
|
||||
void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc);
|
||||
|
@ -286,6 +286,10 @@ namespace Ship {
|
||||
//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) {
|
||||
return gfx_get_pixel_depth(x, y);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ namespace Ship {
|
||||
void Init();
|
||||
void RunCommands(Gfx* Commands);
|
||||
void SetFrameDivisor(int divisor);
|
||||
void GetPixelDepthPrepare(float x, float y);
|
||||
uint16_t GetPixelDepth(float x, float y);
|
||||
void ToggleFullscreen();
|
||||
void SetFullscreen(bool bIsFullscreen);
|
||||
|
@ -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,
|
||||
u8 b, s8 x, s8 y, s8 z);
|
||||
Lights* Lights_New(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambientB);
|
||||
void Lights_GlowCheckPrepare(GlobalContext* globalCtx);
|
||||
void Lights_GlowCheck(GlobalContext* globalCtx);
|
||||
void Lights_DrawGlow(GlobalContext* globalCtx);
|
||||
void ZeldaArena_CheckPointer(void* ptr, size_t size, const char* name, const char* action);
|
||||
|
@ -9,6 +9,7 @@ void Graph_ProcessGfxCommands(Gfx* commands);
|
||||
void OTRLogString(const char* src);
|
||||
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);
|
||||
int32_t OTRGetLastScancode();
|
||||
void ResourceMgr_CacheDirectory(const char* resName);
|
||||
|
@ -24,9 +24,17 @@
|
||||
#include "../soh/Enhancements/debugconsole.h"
|
||||
#include "../soh/Enhancements/debugger/debugger.h"
|
||||
#include "Utils/BitConverter.h"
|
||||
#include "variables.h"
|
||||
|
||||
OTRGlobals* OTRGlobals::Instance;
|
||||
|
||||
static struct {
|
||||
std::condition_variable cv_to_thread, cv_from_thread;
|
||||
std::mutex mutex;
|
||||
bool initialized;
|
||||
bool processing;
|
||||
} audio;
|
||||
|
||||
OTRGlobals::OTRGlobals() {
|
||||
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
|
||||
context->GetWindow()->Init();
|
||||
@ -39,6 +47,10 @@ extern uintptr_t clearMtx;
|
||||
extern "C" Mtx gMtxClear;
|
||||
extern "C" MtxF gMtxFClear;
|
||||
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
|
||||
extern "C" void InitOTR() {
|
||||
@ -80,8 +92,67 @@ extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) {
|
||||
|
||||
// C->C++ Bridge
|
||||
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);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(audio.mutex);
|
||||
while (audio.processing) {
|
||||
audio.cv_from_thread.wait(Lock);
|
||||
}
|
||||
}
|
||||
|
||||
// OTRTODO: FIGURE OUT END FRAME POINT
|
||||
/* if (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;
|
||||
|
||||
extern "C" void OTRSetFrameDivisor(int divisor) {
|
||||
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(divisor);
|
||||
extern "C" void OTRGetPixelDepthPrepare(float x, float y) {
|
||||
OTRGlobals::Instance->context->GetWindow()->GetPixelDepthPrepare(x, y);
|
||||
}
|
||||
|
||||
extern "C" uint16_t OTRGetPixelDepth(float x, float y) {
|
||||
|
@ -24,7 +24,7 @@ void Graph_ProcessFrame(void (*run_one_game_iter)(void));
|
||||
void Graph_ProcessGfxCommands(Gfx* commands);
|
||||
void OTRLogString(const char* src);
|
||||
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);
|
||||
int32_t OTRGetLastScancode();
|
||||
uint32_t ResourceMgr_GetGameVersion();
|
||||
|
@ -469,35 +469,6 @@ static void RunFrame()
|
||||
uint64_t ticksA, ticksB;
|
||||
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);
|
||||
|
||||
|
@ -226,6 +226,9 @@ u16 Environment_GetPixelDepth(s32 x, s32 y) {
|
||||
void Environment_GraphCallback(GraphicsContext* gfxCtx, void* param) {
|
||||
GlobalContext* globalCtx = (GlobalContext*)param;
|
||||
|
||||
OTRGetPixelDepthPrepare(D_8015FD7E, D_8015FD80);
|
||||
Lights_GlowCheckPrepare(globalCtx);
|
||||
|
||||
D_8011FB44 = Environment_GetPixelDepth(D_8015FD7E, D_8015FD80);
|
||||
Lights_GlowCheck(globalCtx);
|
||||
}
|
||||
|
@ -323,6 +323,44 @@ Lights* Lights_New(GraphicsContext* gfxCtx, u8 ambientR, u8 ambientG, u8 ambient
|
||||
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) {
|
||||
LightNode* node;
|
||||
LightPoint* params;
|
||||
|
Loading…
Reference in New Issue
Block a user