From 7c520ae9eec1a2d7ed57121b8b022d61004f20cd Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sat, 29 Sep 2018 01:06:30 +0200 Subject: [PATCH] gs-mipmapper: Implement actual mipmap generation This enables full mipmapping support for textures with a shader view that allows accessing different mip levels. In order to access mip levels, you have to specify gs::texture::flags::BuildMipMaps when creating the texture, as OBS currently forces the maximum mip level to 1 even if you actually have mip data available. --- data/effects/mipgen.effect | 2 +- source/gs-mipmapper.cpp | 98 +++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 40 deletions(-) diff --git a/data/effects/mipgen.effect b/data/effects/mipgen.effect index 152d7596..8514d868 100644 --- a/data/effects/mipgen.effect +++ b/data/effects/mipgen.effect @@ -77,7 +77,7 @@ float4 PSSharpen(VertDataOut v_in) : TARGET float4 PSSmoothen(VertDataOut v_in) : TARGET { - // If we use bilinear and linear sampling, we can get away with just 4 total sampler queries. + // If we use linear sampling, we can get away with just 4 total sampler queries. // However this is not a cheap implementation, it's just meant to be accurate so we do each sampler query and rely on the compiler. float3 smoothKernel3 = float3(0.0574428, 0.0947072, 0.3914000); diff --git a/source/gs-mipmapper.cpp b/source/gs-mipmapper.cpp index 361ccfab..40984057 100644 --- a/source/gs-mipmapper.cpp +++ b/source/gs-mipmapper.cpp @@ -181,57 +181,77 @@ void gs::mipmapper::rebuild(std::shared_ptr source, std::shared_ptr size_t texture_height = source->get_height(); float_t texel_width = 1.0 / texture_width; float_t texel_height = 1.0 / texture_height; + size_t mip_levels = 1; #if defined(WIN32) || defined(WIN64) + ID3D11Texture2D* target_t2; + ID3D11Texture2D* source_t2; if (device_type == GS_DEVICE_DIRECT3D_11) { // We definitely have a Direct3D11 resource. D3D11_TEXTURE2D_DESC target_t2desc; - ID3D11Texture2D* target_t2 = reinterpret_cast(tobj); - ID3D11Texture2D* source_t2 = reinterpret_cast(sobj); - + target_t2 = reinterpret_cast(tobj); + source_t2 = reinterpret_cast(sobj); target_t2->GetDesc(&target_t2desc); - dev->context->CopySubresourceRegion(target_t2, 0, 0, 0, 0, source_t2, 0, nullptr); - - // If we do not have any miplevels, just stop now. - if (target_t2desc.MipLevels == 1) { - obs_leave_graphics(); - return; - } - - for (size_t mip = 1; mip <= target_t2desc.MipLevels; mip++) { - texture_width /= 2; - texture_height /= 2; - texel_width *= 2; - texel_height *= 2; - - // Draw mipmap layer - try { - auto op = render_target->render(texture_width, texture_height); - - effect->get_parameter("image").set_texture(target); - effect->get_parameter("level").set_int(mip); - effect->get_parameter("imageTexel").set_float2(texel_width, texel_height); - effect->get_parameter("strength").set_float(strength); - - while (gs_effect_loop(effect->get_object(), technique.c_str())) { - gs_draw(gs_draw_mode::GS_TRIS, 0, vertex_buffer->size()); - } - } catch (...) { - P_LOG_ERROR("Failed to render mipmap layer."); - } - - // Copy - ID3D11Texture2D* rt = - reinterpret_cast(gs_texture_get_obj(render_target->get_object())); - uint32_t level = D3D11CalcSubresource(mip, 0, target_t2desc.MipLevels); - dev->context->CopySubresourceRegion(target_t2, level, 0, 0, 0, rt, 0, NULL); - } + mip_levels = target_t2desc.MipLevels; } #endif if (device_type == GS_DEVICE_OPENGL) { // This is an OpenGL resource. } + + // If we do not have any miplevels, just stop now. + if (mip_levels == 1) { + obs_leave_graphics(); + return; + } + + for (size_t mip = 1; mip < mip_levels; mip++) { + texture_width /= 2; + texture_height /= 2; + texel_width *= 2; + texel_height *= 2; + + // Draw mipmap layer + try { + auto op = render_target->render(texture_width, texture_height); + + gs_set_cull_mode(GS_NEITHER); + gs_reset_blend_state(); + gs_blend_function_separate(gs_blend_type::GS_BLEND_ONE, gs_blend_type::GS_BLEND_ZERO, + gs_blend_type::GS_BLEND_ONE, gs_blend_type::GS_BLEND_ZERO); + gs_enable_depth_test(false); + gs_enable_stencil_test(false); + gs_enable_stencil_write(false); + gs_enable_color(true, true, true, true); + gs_ortho(0, 1, 0, 1, -1, 1); + + vec4 black; + vec4_zero(&black); + gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0); + + effect->get_parameter("image").set_texture(target); + effect->get_parameter("level").set_int(mip - 1); + effect->get_parameter("imageTexel").set_float2(texel_width, texel_height); + effect->get_parameter("strength").set_float(strength); + + while (gs_effect_loop(effect->get_object(), technique.c_str())) { + gs_draw(gs_draw_mode::GS_TRIS, 0, vertex_buffer->size()); + } + } catch (...) { + P_LOG_ERROR("Failed to render mipmap layer."); + } + +#if defined(WIN32) || defined(WIN64) + if (device_type == GS_DEVICE_DIRECT3D_11) { + // Copy + ID3D11Texture2D* rt = + reinterpret_cast(gs_texture_get_obj(render_target->get_object())); + uint32_t level = D3D11CalcSubresource(mip, 0, mip_levels); + dev->context->CopySubresourceRegion(target_t2, level, 0, 0, 0, rt, 0, NULL); + } +#endif + } } gs_load_indexbuffer(nullptr);