From 8bb4cbae4646f6e58abb9ef217637544867cbf6f Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 21 Apr 2013 14:04:16 +0200 Subject: [PATCH] Avoid complete reinit on apply_state_changes. Clean up multi-pass logic a bit in D3D9. --- gfx/d3d9/d3d9.cpp | 131 +++++++++++++++++++++----------------- gfx/d3d9/d3d9.hpp | 10 +-- gfx/d3d9/render_chain.cpp | 43 ++++++++++++- gfx/d3d9/render_chain.hpp | 2 + 4 files changed, 119 insertions(+), 67 deletions(-) diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp index 2b22cec461..032e6304cb 100644 --- a/gfx/d3d9/d3d9.cpp +++ b/gfx/d3d9/d3d9.cpp @@ -329,28 +329,9 @@ end: return ret; } -bool D3DVideo::viewport_need_restore() -{ - const rarch_viewport_t &custom = g_extern.console.screen.viewports.custom_vp; - if (memcmp(&viewport_state.custom, &custom, sizeof(custom))) - return true; - if (viewport_state.scale_integer != g_settings.video.scale_integer) - return true; - if (fabs(viewport_state.aspect_ratio - g_extern.system.aspect_ratio) > 0.0001) - return true; - - return false; -} - void D3DVideo::calculate_rect(unsigned width, unsigned height, bool keep, float desired_aspect) { - const rarch_viewport_t &custom = g_extern.console.screen.viewports.custom_vp; - - viewport_state.custom = custom; - viewport_state.scale_integer = g_settings.video.scale_integer; - viewport_state.aspect_ratio = desired_aspect; - if (g_settings.video.scale_integer) { struct rarch_viewport vp = {0}; @@ -363,6 +344,7 @@ void D3DVideo::calculate_rect(unsigned width, unsigned height, { if (g_settings.video.aspect_ratio_idx == ASPECT_RATIO_CUSTOM) { + const rarch_viewport_t &custom = g_extern.console.screen.viewports.custom_vp; set_viewport(custom.x, custom.y, custom.width, custom.height); } else @@ -438,6 +420,7 @@ D3DVideo::D3DVideo(const video_info_t *info) : g_pD3D(nullptr), dev(nullptr), font(nullptr), rotation(0), needs_restore(false), cgCtx(nullptr) { + should_resize = false; gfx_set_dwm(); #ifdef HAVE_OVERLAY @@ -611,6 +594,22 @@ bool D3DVideo::frame(const void *frame, return false; } + if (should_resize) + { + calculate_rect(screen_width, screen_height, video_info.force_aspect, g_extern.system.aspect_ratio); + chain->set_final_viewport(final_viewport); + recompute_pass_sizes(); + + // render_chain() only clears out viewport, clear out everything. + D3DRECT clear_rect; + clear_rect.x1 = clear_rect.y1 = 0; + clear_rect.x2 = screen_width; + clear_rect.y2 = screen_height; + dev->Clear(1, &clear_rect, D3DCLEAR_TARGET, 0, 1, 0); + + should_resize = false; + } + if (!chain->render(frame, width, height, pitch, rotation)) { RARCH_ERR("[D3D9]: Failed to render scene.\n"); @@ -803,6 +802,22 @@ void D3DVideo::init_multipass() shader.pass[i].fbo.type_x = shader.pass[i].fbo.type_y = RARCH_SCALE_INPUT; } } + + bool use_extra_pass = shader.passes < GFX_MAX_SHADERS && shader.pass[shader.passes - 1].fbo.valid; + if (use_extra_pass) + { + shader.passes++; + gfx_shader_pass &dummy_pass = shader.pass[shader.passes - 1]; + dummy_pass.fbo.scale_x = dummy_pass.fbo.scale_y = 1.0f; + dummy_pass.fbo.type_x = dummy_pass.fbo.type_y = RARCH_SCALE_VIEWPORT; + dummy_pass.filter = RARCH_FILTER_UNSPEC; + } + else + { + gfx_shader_pass &pass = shader.pass[shader.passes - 1]; + pass.fbo.scale_x = pass.fbo.scale_y = 1.0f; + pass.fbo.type_x = pass.fbo.type_y = RARCH_SCALE_VIEWPORT; + } } bool D3DVideo::set_shader(const std::string &path) @@ -839,6 +854,43 @@ void D3DVideo::process_shader() init_singlepass(); } +void D3DVideo::recompute_pass_sizes() +{ + try + { + LinkInfo link_info = {0}; + link_info.pass = &shader.pass[0]; + link_info.tex_w = link_info.tex_h = video_info.input_scale * RARCH_SCALE_BASE; + + unsigned current_width = link_info.tex_w; + unsigned current_height = link_info.tex_h; + unsigned out_width = 0; + unsigned out_height = 0; + + chain->set_pass_size(0, current_width, current_height); + for (unsigned i = 1; i < shader.passes; i++) + { + RenderChain::convert_geometry(link_info, + out_width, out_height, + current_width, current_height, final_viewport); + + link_info.tex_w = next_pow2(out_width); + link_info.tex_h = next_pow2(out_height); + + chain->set_pass_size(i, link_info.tex_w, link_info.tex_h); + + current_width = out_width; + current_height = out_height; + + link_info.pass = &shader.pass[i]; + } + } + catch (const std::exception& e) + { + RARCH_ERR("[D3D9]: Render chain error: (%s).\n", e.what()); + } +} + bool D3DVideo::init_chain(const video_info_t &video_info) { try @@ -846,14 +898,6 @@ bool D3DVideo::init_chain(const video_info_t &video_info) // Setup information for first pass. LinkInfo link_info = {0}; - if (shader.passes == 1 && !shader.pass[0].fbo.valid) - { - gfx_shader_pass &pass = shader.pass[0]; - pass.filter = video_info.smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST; - pass.fbo.scale_x = pass.fbo.scale_y = 1.0f; - pass.fbo.type_x = pass.fbo.type_y = RARCH_SCALE_VIEWPORT; - } - link_info.pass = &shader.pass[0]; link_info.tex_w = link_info.tex_h = video_info.input_scale * RARCH_SCALE_BASE; @@ -870,8 +914,6 @@ bool D3DVideo::init_chain(const video_info_t &video_info) unsigned out_width = 0; unsigned out_height = 0; - bool use_extra_pass = shader.pass[shader.passes - 1].fbo.valid; - for (unsigned i = 1; i < shader.passes; i++) { RenderChain::convert_geometry(link_info, @@ -885,32 +927,6 @@ bool D3DVideo::init_chain(const video_info_t &video_info) current_width = out_width; current_height = out_height; - if (i == shader.passes - 1 && !use_extra_pass) - { - gfx_shader_pass &pass = shader.pass[i]; - pass.filter = video_info.smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST; - pass.fbo.scale_x = pass.fbo.scale_y = 1.0f; - pass.fbo.type_x = pass.fbo.type_y = RARCH_SCALE_VIEWPORT; - } - - chain->add_pass(link_info); - } - - if (use_extra_pass) - { - RenderChain::convert_geometry(link_info, - out_width, out_height, - current_width, current_height, final_viewport); - - gfx_shader_pass &pass = shader.pass[shader.passes - 1]; - pass.filter = video_info.smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST; - pass.fbo.scale_x = pass.fbo.scale_y = 1.0f; - pass.fbo.type_x = pass.fbo.type_y = RARCH_SCALE_VIEWPORT; - - link_info.pass = &pass; - link_info.tex_w = next_pow2(out_width); - link_info.tex_h = next_pow2(out_height); - chain->add_pass(link_info); } @@ -1409,15 +1425,14 @@ static void d3d9_set_aspect_ratio(void *data, unsigned aspect_ratio_idx) g_extern.system.aspect_ratio = aspectratio_lut[aspect_ratio_idx].value; d3d->info().force_aspect = true; - d3d->restore(); + d3d->should_resize = true; return; } static void d3d9_apply_state_changes(void *data) { D3DVideo *d3d = reinterpret_cast(data); - if (d3d->viewport_need_restore()) - d3d->restore(); + d3d->should_resize = true; } static void d3d9_set_osd_msg(void *data, const char *msg, void *userdata) diff --git a/gfx/d3d9/d3d9.hpp b/gfx/d3d9/d3d9.hpp index 3fd88a49a3..fe5d256b6f 100644 --- a/gfx/d3d9/d3d9.hpp +++ b/gfx/d3d9/d3d9.hpp @@ -95,7 +95,7 @@ class D3DVideo bool restore(); void render_msg(const char *msg, font_params_t *params = nullptr); - bool viewport_need_restore(); + bool should_resize; inline video_info_t& info() { return video_info; } private: @@ -106,13 +106,7 @@ class D3DVideo IDirect3DDevice9 *dev; LPD3DXFONT font; - struct - { - rarch_viewport_t custom; - float aspect_ratio; - bool scale_integer; - } viewport_state; - + void recompute_pass_sizes(); void calculate_rect(unsigned width, unsigned height, bool keep, float aspect); void set_viewport(int x, int y, unsigned width, unsigned height); unsigned screen_width; diff --git a/gfx/d3d9/render_chain.cpp b/gfx/d3d9/render_chain.cpp index e7dd96e136..1841ee72ea 100644 --- a/gfx/d3d9/render_chain.cpp +++ b/gfx/d3d9/render_chain.cpp @@ -108,6 +108,36 @@ void RenderChain::clear() luts.clear(); } +void RenderChain::set_final_viewport(const D3DVIEWPORT9& final_viewport) +{ + this->final_viewport = final_viewport; +} + +void RenderChain::set_pass_size(unsigned pass_index, unsigned width, unsigned height) +{ + Pass &pass = passes[pass_index]; + if (width != pass.info.tex_w || height != pass.info.tex_h) + { + pass.tex->Release(); + pass.info.tex_w = width; + pass.info.tex_h = height; + + if (FAILED(dev->CreateTexture(width, height, 1, + D3DUSAGE_RENDERTARGET, + passes.back().info.pass->fbo.fp_fbo ? D3DFMT_A32B32G32R32F : D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &pass.tex, nullptr))) + { + throw std::runtime_error("Failed to create texture ..."); + } + + dev->SetTexture(0, pass.tex); + dev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); + dev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); + dev->SetTexture(0, nullptr); + } +} + void RenderChain::add_pass(const LinkInfo &info) { Pass pass; @@ -620,7 +650,18 @@ void RenderChain::render_pass(Pass &pass, unsigned pass_index) bind_luts(pass); bind_tracker(pass, pass_index); - dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0); + // Clear out whole framebuffer incase we change viewports mid-way to avoid stale garbage. + if (pass_index < passes.size()) + { + D3DRECT clear_rect; + clear_rect.x1 = clear_rect.y1 = 0; + clear_rect.x2 = passes[pass_index].info.tex_w; + clear_rect.y2 = passes[pass_index].info.tex_h; + dev->Clear(1, &clear_rect, D3DCLEAR_TARGET, 0, 1, 0); + } + else + dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1, 0); + if (SUCCEEDED(dev->BeginScene())) { dev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); diff --git a/gfx/d3d9/render_chain.hpp b/gfx/d3d9/render_chain.hpp index 0a5b49880e..9931e503f0 100644 --- a/gfx/d3d9/render_chain.hpp +++ b/gfx/d3d9/render_chain.hpp @@ -51,6 +51,8 @@ class RenderChain PixelFormat fmt, const D3DVIEWPORT9 &final_viewport); + void set_pass_size(unsigned pass, unsigned width, unsigned height); + void set_final_viewport(const D3DVIEWPORT9 &final_viewport); void add_pass(const LinkInfo &info); void add_lut(const std::string &id, const std::string &path, bool smooth); void add_state_tracker(std::shared_ptr tracker);