From 12e50816187636472965ba05bca2c4d57b75f0b7 Mon Sep 17 00:00:00 2001 From: Kyle Gospodnetich Date: Tue, 8 Oct 2024 08:14:32 -0700 Subject: [PATCH] feat(gamescope): Add Ally display patch and bicubic filter patch --- spec_files/gamescope/740.patch | 1012 +++++++++++++++++++++++ spec_files/gamescope/ally-display.patch | 101 +++ spec_files/gamescope/gamescope.spec | 8 +- 3 files changed, 1120 insertions(+), 1 deletion(-) create mode 100644 spec_files/gamescope/740.patch create mode 100644 spec_files/gamescope/ally-display.patch diff --git a/spec_files/gamescope/740.patch b/spec_files/gamescope/740.patch new file mode 100644 index 00000000..97a763f3 --- /dev/null +++ b/spec_files/gamescope/740.patch @@ -0,0 +1,1012 @@ +From 564a689c2b293d2e894bf1edb14eb0f78bde8725 Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Sat, 5 Oct 2024 14:40:23 -0300 +Subject: [PATCH 1/9] Partial bicubic code adaptation + +--- + src/Backends/SDLBackend.cpp | 4 + + src/Backends/WaylandBackend.cpp | 1 + + src/main.cpp | 29 ++++++ + src/main.hpp | 15 +++ + src/meson.build | 1 + + src/rendervulkan.cpp | 64 +++++++++++- + src/rendervulkan.hpp | 2 + + src/shaders/bicubic.h | 44 ++++++++ + src/shaders/cs_bicubic.comp | 176 ++++++++++++++++++++++++++++++++ + src/steamcompmgr.cpp | 6 ++ + 10 files changed, 341 insertions(+), 1 deletion(-) + create mode 100644 src/shaders/bicubic.h + create mode 100644 src/shaders/cs_bicubic.comp + +diff --git a/src/Backends/SDLBackend.cpp b/src/Backends/SDLBackend.cpp +index 6d50f8d34..c24b864c6 100644 +--- a/src/Backends/SDLBackend.cpp ++++ b/src/Backends/SDLBackend.cpp +@@ -719,6 +719,10 @@ namespace gamescope + case KEY_B: + g_wantedUpscaleFilter = GamescopeUpscaleFilter::LINEAR; + break; ++ case KEY_K: ++ g_wantedDownscaleFilter = (g_wantedDownscaleFilter == GamescopeDownscaleFilter::BICUBIC) ? ++ GamescopeDownscaleFilter::LINEAR : GamescopeDownscaleFilter::BICUBIC; ++ break; + case KEY_U: + g_wantedUpscaleFilter = (g_wantedUpscaleFilter == GamescopeUpscaleFilter::FSR) ? + GamescopeUpscaleFilter::LINEAR : GamescopeUpscaleFilter::FSR; +diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp +index c53bf14df..d0abb2fa2 100644 +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -1598,6 +1598,7 @@ namespace gamescope + bNeedsFullComposite |= cv_composite_force; + bNeedsFullComposite |= pFrameInfo->useFSRLayer0; + bNeedsFullComposite |= pFrameInfo->useNISLayer0; ++ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; + bNeedsFullComposite |= pFrameInfo->blurLayer0; + bNeedsFullComposite |= bNeedsCompositeFromFilter; + bNeedsFullComposite |= g_bColorSliderInUse; +diff --git a/src/main.cpp b/src/main.cpp +index a9cdaa2e2..ed7fd4fa7 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #if defined(__linux__) + #include +@@ -63,6 +64,7 @@ const struct option *gamescope_options = (struct option[]){ + { "output-height", required_argument, nullptr, 'H' }, + { "sharpness", required_argument, nullptr, 0 }, + { "fsr-sharpness", required_argument, nullptr, 0 }, ++ { "bicubic", optional_argument, nullptr, 'D' }, + { "rt", no_argument, nullptr, 0 }, + { "prefer-vk-device", required_argument, 0 }, + { "expose-wayland", no_argument, 0 }, +@@ -288,11 +290,14 @@ bool g_bGrabbed = false; + float g_mouseSensitivity = 1.0; + + GamescopeUpscaleFilter g_upscaleFilter = GamescopeUpscaleFilter::LINEAR; ++GamescopeDownscaleFilter g_downscaleFilter = GamescopeDownscaleFilter::LINEAR; + GamescopeUpscaleScaler g_upscaleScaler = GamescopeUpscaleScaler::AUTO; + + GamescopeUpscaleFilter g_wantedUpscaleFilter = GamescopeUpscaleFilter::LINEAR; ++GamescopeDownscaleFilter g_wantedDownscaleFilter = GamescopeDownscaleFilter::LINEAR; + GamescopeUpscaleScaler g_wantedUpscaleScaler = GamescopeUpscaleScaler::AUTO; + int g_upscaleFilterSharpness = 2; ++GamescopeBicubicParams g_bicubicParams; + + gamescope::GamescopeModeGeneration g_eGamescopeModeGeneration = gamescope::GAMESCOPE_MODE_GENERATE_CVT; + +@@ -397,6 +402,27 @@ static enum GamescopeUpscaleFilter parse_upscaler_filter(const char *str) + } + } + ++static enum GamescopeDownscaleFilter parse_downscaling_filter(const char *str) ++{ ++ std::stringstream ss{optarg}; ++ ++ double b, c; ++ char comma; ++ if ((ss >> b >> comma >> c) && (comma == ',')) { ++ // clamp values ++ b = std::clamp(b, 0.0, 1.0); ++ c = std::clamp(c, 0.0, 1.0); ++ // Ovewrite default global parameters ++ g_bicubicParams.b = b; ++ g_bicubicParams.c = c; ++ // Set downscaling filters ++ return GamescopeDownscaleFilter::BICUBIC; ++ } ++ ++ fprintf( stderr, "gamescope: invalid value for --bicubic\n" ); ++ exit(1); ++} ++ + static enum gamescope::GamescopeBackend parse_backend_name(const char *str) + { + if (strcmp(str, "auto") == 0) { +@@ -704,6 +730,9 @@ int main(int argc, char **argv) + case 'F': + g_wantedUpscaleFilter = parse_upscaler_filter(optarg); + break; ++ case 'D': ++ g_wantedDownscaleFilter = parse_downscaling_filter(optarg); ++ break; + case 'b': + g_bBorderlessOutputWindow = true; + break; +diff --git a/src/main.hpp b/src/main.hpp +index 2e6fb833a..f8cc03053 100644 +--- a/src/main.hpp ++++ b/src/main.hpp +@@ -40,6 +40,18 @@ enum class GamescopeUpscaleFilter : uint32_t + FROM_VIEW = 0xF, // internal + }; + ++enum class GamescopeDownscaleFilter : uint32_t ++{ ++ LINEAR = 0, ++ BICUBIC, ++}; ++ ++struct GamescopeBicubicParams ++{ ++ float b = 0.3f; ++ float c = 0.3f; ++}; ++ + static constexpr bool DoesHardwareSupportUpscaleFilter( GamescopeUpscaleFilter eFilter ) + { + // Could do nearest someday... AMDGPU DC supports custom tap placement to an extent. +@@ -57,10 +69,13 @@ enum class GamescopeUpscaleScaler : uint32_t + }; + + extern GamescopeUpscaleFilter g_upscaleFilter; ++extern GamescopeDownscaleFilter g_downscaleFilter; + extern GamescopeUpscaleScaler g_upscaleScaler; + extern GamescopeUpscaleFilter g_wantedUpscaleFilter; ++extern GamescopeDownscaleFilter g_wantedDownscaleFilter; + extern GamescopeUpscaleScaler g_wantedUpscaleScaler; + extern int g_upscaleFilterSharpness; ++extern GamescopeBicubicParams g_bicubicParams; + + extern bool g_bBorderlessOutputWindow; + +diff --git a/src/meson.build b/src/meson.build +index 5174de670..907277a23 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -66,6 +66,7 @@ shader_src = [ + 'shaders/cs_composite_rcas.comp', + 'shaders/cs_easu.comp', + 'shaders/cs_easu_fp16.comp', ++ 'shaders/cs_bicubic.comp', + 'shaders/cs_gaussian_blur_horizontal.comp', + 'shaders/cs_nis.comp', + 'shaders/cs_nis_fp16.comp', +diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp +index d61fd73ea..45f45deba 100644 +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -44,6 +44,7 @@ + #include "cs_composite_rcas.h" + #include "cs_easu.h" + #include "cs_easu_fp16.h" ++#include "cs_bicubic.h" + #include "cs_gaussian_blur_horizontal.h" + #include "cs_nis.h" + #include "cs_nis_fp16.h" +@@ -52,6 +53,7 @@ + #define A_CPU + #include "shaders/ffx_a.h" + #include "shaders/ffx_fsr1.h" ++#include "shaders/bicubic.h" + + #include "reshade_effect_manager.hpp" + +@@ -890,11 +892,13 @@ bool CVulkanDevice::createShaders() + if (m_bSupportsFp16) + { + SHADER(EASU, cs_easu_fp16); ++ SHADER(BICUBIC, cs_bicubic); + SHADER(NIS, cs_nis_fp16); + } + else + { + SHADER(EASU, cs_easu); ++ SHADER(BICUBIC, cs_bicubic); + SHADER(NIS, cs_nis); + } + SHADER(RGB_TO_NV12, cs_rgb_to_nv12); +@@ -1126,6 +1130,7 @@ void CVulkanDevice::compileAllPipelines() + SHADER(BLUR_FIRST_PASS, 1, 2, 1); + SHADER(RCAS, k_nMaxLayers, k_nMaxYcbcrMask_ToPreCompile, 1); + SHADER(EASU, 1, 1, 1); ++ SHADER(BICUBIC, 1, 1, 1); + SHADER(NIS, 1, 1, 1); + SHADER(RGB_TO_NV12, 1, 1, 1); + #undef SHADER +@@ -3691,6 +3696,17 @@ struct EasuPushData_t + } + }; + ++struct BicubicPushData_t ++{ ++ uvec4_t Const0; ++ uvec4_t Const1; ++ ++ BicubicPushData_t(float B, float C, uint32_t inputX, uint32_t inputY, uint32_t tempX, uint32_t tempY, uint32_t winX, uint32_t winY) ++ { ++ BicubicCon(&Const0.x, &Const1.x, B*10, C*10, inputX, inputY, tempX, tempY, winX, winY); ++ } ++}; ++ + struct RcasPushData_t + { + uvec2_t u_layer0Offset; +@@ -3900,7 +3916,53 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco + for (uint32_t i = 0; i < EOTF_Count; i++) + cmdBuffer->bindColorMgmtLuts(i, frameInfo->shaperLut[i], frameInfo->lut3D[i]); + +- if ( frameInfo->useFSRLayer0 ) ++ if ( frameInfo->useBICUBICLayer0 ) ++ { ++ // fprintf(stderr, "-- Use bicubic\n"); ++ uint32_t inputX = frameInfo->layers[0].tex->width(); ++ uint32_t inputY = frameInfo->layers[0].tex->height(); ++ ++ uint32_t tempX = frameInfo->layers[0].integerWidth(); ++ uint32_t tempY = frameInfo->layers[0].integerHeight(); ++ ++ update_tmp_images(tempX, tempY); ++ ++ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BICUBIC, frameInfo->layerCount, frameInfo->ycbcrMask())); ++ // cmdBuffer->bindTarget(compositeImage); ++ cmdBuffer->bindTarget(g_output.tmpOutput); ++ cmdBuffer->bindTexture(0, frameInfo->layers[0].tex); ++ cmdBuffer->setTextureSrgb(0, true); ++ cmdBuffer->setSamplerUnnormalized(0, false); ++ cmdBuffer->setSamplerNearest(0, false); ++ cmdBuffer->uploadConstants(g_bicubicParams.b ++ , g_bicubicParams.c ++ , inputX ++ , inputY ++ , tempX ++ , tempY ++ , currentOutputWidth ++ , currentOutputHeight ++ ); ++ ++ int pixelsPerGroup = 16; ++ ++ cmdBuffer->dispatch(div_roundup(tempX, pixelsPerGroup), div_roundup(tempY, pixelsPerGroup)); ++ ++ struct FrameInfo_t bicFrameInfo = *frameInfo; ++ bicFrameInfo.layers[0].tex = g_output.tmpOutput; ++ bicFrameInfo.layers[0].scale.x = 1.0f; ++ bicFrameInfo.layers[0].scale.y = 1.0f; ++ ++ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, bicFrameInfo.layerCount, bicFrameInfo.ycbcrMask())); ++ bind_all_layers(cmdBuffer.get(), &bicFrameInfo); ++ cmdBuffer->bindTarget(compositeImage); ++ cmdBuffer->uploadConstants(&bicFrameInfo); ++ ++ pixelsPerGroup = 8; ++ ++ cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); ++ } ++ else if ( frameInfo->useFSRLayer0 ) + { + uint32_t inputX = frameInfo->layers[0].tex->width(); + uint32_t inputY = frameInfo->layers[0].tex->height(); +diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp +index b967e849f..f6b80c5a1 100644 +--- a/src/rendervulkan.hpp ++++ b/src/rendervulkan.hpp +@@ -269,6 +269,7 @@ struct FrameInfo_t + { + bool useFSRLayer0; + bool useNISLayer0; ++ bool useBICUBICLayer0; + bool bFadingOut; + BlurMode blurLayer0; + int blurRadius; +@@ -530,6 +531,7 @@ enum ShaderType { + SHADER_TYPE_EASU, + SHADER_TYPE_RCAS, + SHADER_TYPE_NIS, ++ SHADER_TYPE_BICUBIC, + SHADER_TYPE_RGB_TO_NV12, + + SHADER_TYPE_COUNT +diff --git a/src/shaders/bicubic.h b/src/shaders/bicubic.h +new file mode 100644 +index 000000000..8117e8783 +--- /dev/null ++++ b/src/shaders/bicubic.h +@@ -0,0 +1,44 @@ ++//_____________________________________________________________/\_______________________________________________________________ ++//============================================================================================================================== ++// ++// ++// BICUBIC IMAGE SCALING ++// ++// ++//------------------------------------------------------------------------------------------------------------------------------ ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ++//_____________________________________________________________/\_______________________________________________________________ ++//============================================================================================================================== ++// CONSTANT SETUP ++//============================================================================================================================== ++// Call to setup required constant values (works on CPU or GPU). ++A_STATIC void BicubicCon( ++outAU4 con0, ++outAU4 con1, ++// Configurable parameters ++AU1 B, ++AU1 C, ++// This the rendered image resolution ++AF1 inputRenderedSizeX, ++AF1 inputRenderedSizeY, ++// This is the resolution of the resource containing the input image (useful for dynamic resolution) ++AF1 inputCurrentSizeX, ++AF1 inputCurrentSizeY, ++// This is the window width / height ++AF1 outputTargetSizeX, ++AF1 outputTargetSizeY) ++{ ++ // Input/Output size information ++ con0[0]=AU1_AF1(inputRenderedSizeX); ++ con0[1]=AU1_AF1(inputRenderedSizeY); ++ con0[2]=AU1_AF1(inputCurrentSizeX); ++ con0[3]=AU1_AF1(inputCurrentSizeY); ++ ++ // Viewport pixel position to normalized image space. ++ con1[0]=AU1_AF1(outputTargetSizeX); ++ con1[1]=AU1_AF1(outputTargetSizeY); ++ con1[2]=B; ++ con1[3]=C; ++} +diff --git a/src/shaders/cs_bicubic.comp b/src/shaders/cs_bicubic.comp +new file mode 100644 +index 000000000..4904433b5 +--- /dev/null ++++ b/src/shaders/cs_bicubic.comp +@@ -0,0 +1,176 @@ ++// References ++// https://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL ++// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl ++// https://web.archive.org/web/20180927181721/http://www.java-gaming.org/index.php?topic=35123.0 ++// https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1 ++ ++#version 460 ++ ++#extension GL_GOOGLE_include_directive : require ++#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require ++ ++#include "descriptor_set.h" ++ ++layout( ++ local_size_x = 64, ++ local_size_y = 1, ++ local_size_z = 1) in; ++ ++// Push constant is a mechanism in modern OpenGL that allows passing small amounts of frequently ++// updated data to the shader without needing to bind a buffer ++layout(push_constant) ++uniform layers_t { ++ uvec4 c0, c1; ++}; ++ ++#define A_GPU 1 ++#define A_GLSL 1 ++#define A_HALF 1 ++#include "ffx_a.h" ++#include "bicubic.h" ++ ++// The Mitchell–Netravali filters or BC-splines ++// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters ++// Conditionals are slow in GPU code, so to represent 0 <= f < 1 and 1 <= f < 2 ++// the P(d) form shown in the wikipedia page is used ++vec4 mitchellNetravaliWeights(float f, float B, float C) ++{ ++ float w0 = ((12.0 - 9.0 * B - 6.0 * C) * pow(f, 3.0)) + ++ ((-18.0 + 12.0 * B + 6.0 * C) * pow(f, 2.0)) + ++ (6.0 - 2.0 * B); ++ ++ float w1 = ((-B - 6.0 * C) * pow(f - 1.0, 3.0)) + ++ ((6.0 * B + 30.0 * C) * pow(f - 1.0, 2.0)) + ++ ((-12.0 * B - 48.0 * C) * (f - 1.0)) + ++ (8.0 * B + 24.0 * C); ++ ++ float w2 = ((12.0 - 9.0 * B - 6.0 * C) * pow(1.0 - f, 3.0)) + ++ ((-18.0 + 12.0 * B + 6.0 * C) * pow(1.0 - f, 2.0)) + ++ (6.0 - 2.0 * B); ++ ++ float w3 = ((-B - 6.0 * C) * pow(2.0 - f, 3.0)) + ++ ((6.0 * B + 30.0 * C) * pow(2.0 - f, 2.0)) + ++ ((-12.0 * B - 48.0 * C) * (2.0 - f)) + ++ (8.0 * B + 24.0 * C); ++ ++ return vec4(w0, w1, w2, w3); ++} ++ ++// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl ++// https://web.archive.org/web/20180927181721/http://www.java-gaming.org/index.php?topic=35123.0 ++// This is an efficient method to implement bicubic filtering, it takes ++// advantage of the fact that the bilinear approach gives the weighted average ++// of a 2x2 area. ++vec4 textureBicubic(sampler2D splr, vec2 texCoords) ++{ ++ vec2 texSize = textureSize(splr, 0); ++ vec2 invTexSize = 1.0 / texSize; ++ ++ // Converts normalized coordinates into pixel-space coordinate ++ // Example: If texCoords is (0.5, 0.5), and the texture size is (1920, 1080), the result will be ++ // (960, 540)—the center of the texture in pixel space. ++ // Subtracting 0.5 ensures that you're sampling from the center of the texel rather than its corner ++ // Example: Assume we have a 3x3 texture and texCoords = (0.5, 0.5): ++ // [0,0][1,0][2,0] ++ // [0,1][1,1][2,1] ++ // [0,2][1,2][2,2] ++ // texCoords * texSize - 0.5 maps to (1.5, 1.5), which is between (1,1) and (2,2), then ++ // subtracts 0.5 to move it to (1.0, 1.0)—the center of the texel ++ texCoords = texCoords * texSize - 0.5; ++ ++ // Get B and C that were pushed from the user input (or default values) ++ float B = c1[2] / 10.0f; ++ float C = c1[3] / 10.0f; ++ ++ // Get the fractional part of the coordinates ++ // They are used in Mitchell Netravali's strategy to calculate the interpolation weights, ++ // i.e., how much influence the neighboring vertices have on the final pixel value ++ vec2 fxy = fract(texCoords); ++ texCoords -= fxy; ++ ++ // Calculate bicubic weights ++ // These weights represent how much influence each neighboring texel in the 4x4 grid will have ++ // on the final interpolated pixel value ++ vec4 xweights = mitchellNetravaliWeights(fxy.x, B, C); ++ vec4 yweights = mitchellNetravaliWeights(fxy.y, B, C); ++ ++ // Modify the current texture coordinates to have an offset in texels for each coordinate ++ // E.g. texCoords + vec(-1.0, 0.0) is a texel to the left ++ // texCoords + vec(1.0, 0.0) is a texel to the right ++ // texCoords + vec(0.0, 1.0) is a texel downwards ++ // texCoords + vec(0.0, -1.0) is a texel upwards ++ vec4 offsetTexels = texCoords.xxyy; ++ offsetTexels += vec2 (-1.0, +1.0).xyxy; ++ // Normalize weights to range between (0,1) ++ // vec4 sumWeights = vec4(xweights.xz + xweights.yw, yweights.xz + yweights.yw); ++ // vec4 normalizedWeights = vec4 (xweights.yw, yweights.yw) / sumWeights; ++ vec4 sumWeights = vec4(xweights.x + xweights.y, xweights.z + xweights.w, yweights.x + yweights.y, yweights.z + yweights.w); ++ vec4 normalizedWeights = vec4 (xweights.y, xweights.w, yweights.y, yweights.w) / sumWeights; ++ // Use the weights to influence the sampling position inside each texel ++ // Each texel has a size from (0,1) ++ vec4 offsetSampler = offsetTexels + normalizedWeights; ++ // Go back to normalized space ++ offsetSampler *= invTexSize.xxyy; ++ // Perform the sampling ++ vec4 sample0 = texture(splr, offsetSampler.xz); ++ vec4 sample1 = texture(splr, offsetSampler.yz); ++ vec4 sample2 = texture(splr, offsetSampler.xw); ++ vec4 sample3 = texture(splr, offsetSampler.yw); ++ ++ // Now we perform linear interpolation in the selected points ++ // The mix(a, b, t) function in GLSL performs linear interpolation between a and b based on the ++ // parameter t, t is between 0 and 1 ++ // https://registry.khronos.org/OpenGL-Refpages/gl4/html/mix.xhtml ++ ++ // Here we want to normalize sx and sy to between 0 and 1 (t value) ++ float sx = sumWeights.x / (sumWeights.x + sumWeights.y); ++ float sy = sumWeights.z / (sumWeights.z + sumWeights.w); ++ ++ return mix( ++ mix(sample3, sample2, sx), mix(sample1, sample0, sx) ++ , sy); ++} ++ ++void bicPass(uvec2 pos) ++{ ++ // Retrieve pushed values ++ AF2 inputRenderedSize = AF2_AU2(c0.xy); ++ AF2 inputCurrentSize = AF2_AU2(c0.zw); ++ AF2 outputTargetSize = AF2_AU2(c1.xy); ++ ++ // ARcpF1(x) == 1.0 / x ++ // scaleFactor is the division between the rendered image and the size it should have at the end ++ // E.g.: Rendered 1920x1080, window size is 960x540, then scaleFactor is 2x2 ++ AF2 scaleFactor = inputRenderedSize * vec2(ARcpF1(inputCurrentSize.x), ARcpF1(inputCurrentSize.y)); ++ ++ // The parameter pos of this function is used to iterate over the output image (e.g. 960x540) ++ // The position of the processed pixel should be taken from the rendered image (e.g. 1920x1080) ++ // 10x10 in the output, corresponds to 20x20 in the original image ++ AF2 positionPixel=AF2(pos)*scaleFactor; ++ ++ // Normalize the image space to be between [0,1] ++ positionPixel=positionPixel*vec2(ARcpF1(inputRenderedSize.x),ARcpF1(inputRenderedSize.y)); ++ ++ // Apply the bicubic algorithm in the normalized pixel position ++ vec4 bicPass = textureBicubic(s_samplers[0], positionPixel); ++ ++ imageStore(dst, ivec2(pos), bicPass); ++} ++ ++ ++void main() ++{ ++ // AMD recommends to use this swizzle and to process 4 pixel per invocation ++ // for better cache utilisation ++ uvec2 pos = ARmp8x8(gl_LocalInvocationID.x) + uvec2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u); ++ ++ bicPass(pos); ++ pos.x += 8u; ++ bicPass(pos); ++ pos.y += 8u; ++ bicPass(pos); ++ pos.x -= 8u; ++ bicPass(pos); ++} ++ ++/* vim: set expandtab ft=cpp fdm=marker ts=4 sw=4 tw=100 et :*/ +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 02148f423..b33608707 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -2356,6 +2356,10 @@ paint_all(bool async) + paint_window(w, w, &frameInfo, global_focus.cursor, PaintWindowFlag::BasePlane | PaintWindowFlag::DrawBorders, 1.0f, override); + + bool needsScaling = frameInfo.layers[0].scale.x < 0.999f && frameInfo.layers[0].scale.y < 0.999f; ++ // Temporarily allow upscaling as well ++ // bool needsDownScaling = frameInfo.layers[0].scale.x > 1.001f && frameInfo.layers[0].scale.y > 1.001f; ++ bool needsDownScaling = true; ++ frameInfo.useBICUBICLayer0 = g_downscaleFilter == GamescopeDownscaleFilter::BICUBIC && needsDownScaling; + frameInfo.useFSRLayer0 = g_upscaleFilter == GamescopeUpscaleFilter::FSR && needsScaling; + frameInfo.useNISLayer0 = g_upscaleFilter == GamescopeUpscaleFilter::NIS && needsScaling; + } +@@ -2488,6 +2492,7 @@ paint_all(bool async) + } + + frameInfo.useFSRLayer0 = false; ++ frameInfo.useBICUBICLayer0 = false; + frameInfo.useNISLayer0 = false; + } + +@@ -7846,6 +7851,7 @@ steamcompmgr_main(int argc, char **argv) + g_bSteamIsActiveWindow = false; + g_upscaleScaler = g_wantedUpscaleScaler; + g_upscaleFilter = g_wantedUpscaleFilter; ++ g_downscaleFilter = g_wantedDownscaleFilter; + } + + // If we're in the middle of a fade, then keep us + +From 6acfb50f09cc9fd8a16dd502d260b920a8ba02cb Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Sat, 5 Oct 2024 15:19:23 -0300 +Subject: [PATCH 2/9] Partial bicubic code adaptation [2] + +--- + src/Backends/DRMBackend.cpp | 1 + + src/Backends/OpenVRBackend.cpp | 1 + + src/main.cpp | 6 +++--- + src/rendervulkan.cpp | 3 +-- + src/shaders/descriptor_set.h | 1 + + src/steamcompmgr.cpp | 17 +++++++++++++++++ + src/steamcompmgr.hpp | 1 + + src/xwayland_ctx.hpp | 1 + + 8 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp +index c62635f19..76c9f0514 100644 +--- a/src/Backends/DRMBackend.cpp ++++ b/src/Backends/DRMBackend.cpp +@@ -3211,6 +3211,7 @@ namespace gamescope + bNeedsFullComposite |= bWasFirstFrame; + bNeedsFullComposite |= pFrameInfo->useFSRLayer0; + bNeedsFullComposite |= pFrameInfo->useNISLayer0; ++ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; + bNeedsFullComposite |= pFrameInfo->blurLayer0; + bNeedsFullComposite |= bNeedsCompositeFromFilter; + bNeedsFullComposite |= !k_bUseCursorPlane && bDrewCursor; +diff --git a/src/Backends/OpenVRBackend.cpp b/src/Backends/OpenVRBackend.cpp +index c39caa54b..08640f853 100644 +--- a/src/Backends/OpenVRBackend.cpp ++++ b/src/Backends/OpenVRBackend.cpp +@@ -554,6 +554,7 @@ namespace gamescope + bNeedsFullComposite |= cv_composite_force; + bNeedsFullComposite |= pFrameInfo->useFSRLayer0; + bNeedsFullComposite |= pFrameInfo->useNISLayer0; ++ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; + bNeedsFullComposite |= pFrameInfo->blurLayer0; + bNeedsFullComposite |= bNeedsCompositeFromFilter; + bNeedsFullComposite |= g_bColorSliderInUse; +diff --git a/src/main.cpp b/src/main.cpp +index ed7fd4fa7..de25ddeab 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -402,7 +402,7 @@ static enum GamescopeUpscaleFilter parse_upscaler_filter(const char *str) + } + } + +-static enum GamescopeDownscaleFilter parse_downscaling_filter(const char *str) ++static enum GamescopeDownscaleFilter parse_downscaler_filter(const char *str) + { + std::stringstream ss{optarg}; + +@@ -415,7 +415,7 @@ static enum GamescopeDownscaleFilter parse_downscaling_filter(const char *str) + // Ovewrite default global parameters + g_bicubicParams.b = b; + g_bicubicParams.c = c; +- // Set downscaling filters ++ // Set downscaler filters + return GamescopeDownscaleFilter::BICUBIC; + } + +@@ -731,7 +731,7 @@ int main(int argc, char **argv) + g_wantedUpscaleFilter = parse_upscaler_filter(optarg); + break; + case 'D': +- g_wantedDownscaleFilter = parse_downscaling_filter(optarg); ++ g_wantedDownscaleFilter = parse_downscaler_filter(optarg); + break; + case 'b': + g_bBorderlessOutputWindow = true; +diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp +index 45f45deba..e80afb68a 100644 +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -889,16 +889,15 @@ bool CVulkanDevice::createShaders() + SHADER(BLUR_COND, cs_composite_blur_cond); + SHADER(BLUR_FIRST_PASS, cs_gaussian_blur_horizontal); + SHADER(RCAS, cs_composite_rcas); ++ SHADER(BICUBIC, cs_bicubic); + if (m_bSupportsFp16) + { + SHADER(EASU, cs_easu_fp16); +- SHADER(BICUBIC, cs_bicubic); + SHADER(NIS, cs_nis_fp16); + } + else + { + SHADER(EASU, cs_easu); +- SHADER(BICUBIC, cs_bicubic); + SHADER(NIS, cs_nis); + } + SHADER(RGB_TO_NV12, cs_rgb_to_nv12); +diff --git a/src/shaders/descriptor_set.h b/src/shaders/descriptor_set.h +index f2b8527c8..64cc1c9c3 100644 +--- a/src/shaders/descriptor_set.h ++++ b/src/shaders/descriptor_set.h +@@ -21,6 +21,7 @@ const int filter_nearest = 1; + const int filter_fsr = 2; + const int filter_nis = 3; + const int filter_pixel = 4; ++const int filter_bicubic = 5; + const int filter_from_view = 255; + + const int EOTF_Gamma22 = 0; +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index b33608707..86a815f06 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -874,6 +874,7 @@ gamescope::ConCommand cc_debug_set_fps_limit( "debug_set_fps_limit", "Set refres + static int g_nRuntimeInfoFd = -1; + + bool g_bFSRActive = false; ++bool g_bBicubicActive = false; + + BlurMode g_BlurMode = BLUR_MODE_OFF; + BlurMode g_BlurModeOld = BLUR_MODE_OFF; +@@ -2497,6 +2498,7 @@ paint_all(bool async) + } + + g_bFSRActive = frameInfo.useFSRLayer0; ++ g_bBicubicActive = frameInfo.useBICUBICLayer0; + + g_bFirstFrame = false; + +@@ -5417,6 +5419,9 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + g_wantedUpscaleScaler = GamescopeUpscaleScaler::AUTO; + g_wantedUpscaleFilter = GamescopeUpscaleFilter::NIS; + break; ++ case 5: ++ g_wantedDownscaleFilter = GamescopeDownscaleFilter::BICUBIC; ++ break; + } + hasRepaint = true; + } +@@ -6969,6 +6974,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ + ctx->atoms.gamescopeLowLatency = XInternAtom( ctx->dpy, "GAMESCOPE_LOW_LATENCY", false ); + + ctx->atoms.gamescopeFSRFeedback = XInternAtom( ctx->dpy, "GAMESCOPE_FSR_FEEDBACK", false ); ++ ctx->atoms.gamescopeBicubicFeedback = XInternAtom( ctx->dpy, "GAMESCOPE_BICUBIC_FEEDBACK", false ); + + ctx->atoms.gamescopeBlurMode = XInternAtom( ctx->dpy, "GAMESCOPE_BLUR_MODE", false ); + ctx->atoms.gamescopeBlurRadius = XInternAtom( ctx->dpy, "GAMESCOPE_BLUR_RADIUS", false ); +@@ -7224,6 +7230,7 @@ extern int g_nPreferredOutputWidth; + extern int g_nPreferredOutputHeight; + + static bool g_bWasFSRActive = false; ++static bool g_bWasBicubicActive = false; + + bool g_bAppWantsHDRCached = false; + +@@ -7615,6 +7622,16 @@ steamcompmgr_main(int argc, char **argv) + flush_root = true; + } + ++ if ( g_bBicubicActive != g_bWasBicubicActive ) ++ { ++ uint32_t active = g_bBicubicActive ? 1 : 0; ++ XChangeProperty( root_ctx->dpy, root_ctx->root, root_ctx->atoms.gamescopeBicubicFeedback, XA_CARDINAL, 32, PropModeReplace, ++ (unsigned char *)&active, 1 ); ++ ++ g_bWasBicubicActive = g_bBicubicActive; ++ flush_root = true; ++ } ++ + if (global_focus.IsDirty()) + determine_and_apply_focus(); + +diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp +index 9f384c461..ea0746860 100644 +--- a/src/steamcompmgr.hpp ++++ b/src/steamcompmgr.hpp +@@ -128,6 +128,7 @@ extern float focusedWindowOffsetX; + extern float focusedWindowOffsetY; + + extern bool g_bFSRActive; ++extern bool g_bBicubicActive; + + extern uint32_t inputCounter; + extern uint64_t g_lastWinSeq; +diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp +index df2af70d1..e212a119e 100644 +--- a/src/xwayland_ctx.hpp ++++ b/src/xwayland_ctx.hpp +@@ -164,6 +164,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable + Atom gamescopeLowLatency; + + Atom gamescopeFSRFeedback; ++ Atom gamescopeBicubicFeedback; + + Atom gamescopeBlurMode; + Atom gamescopeBlurRadius; + +From fceb9b90021e0abf2da6e8cff71034dc204afb24 Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 00:37:49 -0300 +Subject: [PATCH 3/9] Fix indentation + +--- + src/Backends/OpenVRBackend.cpp | 2 +- + src/Backends/WaylandBackend.cpp | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/Backends/OpenVRBackend.cpp b/src/Backends/OpenVRBackend.cpp +index 08640f853..96a3d0166 100644 +--- a/src/Backends/OpenVRBackend.cpp ++++ b/src/Backends/OpenVRBackend.cpp +@@ -554,7 +554,7 @@ namespace gamescope + bNeedsFullComposite |= cv_composite_force; + bNeedsFullComposite |= pFrameInfo->useFSRLayer0; + bNeedsFullComposite |= pFrameInfo->useNISLayer0; +- bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; ++ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; + bNeedsFullComposite |= pFrameInfo->blurLayer0; + bNeedsFullComposite |= bNeedsCompositeFromFilter; + bNeedsFullComposite |= g_bColorSliderInUse; +diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp +index d0abb2fa2..d9d213e85 100644 +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -1598,7 +1598,7 @@ namespace gamescope + bNeedsFullComposite |= cv_composite_force; + bNeedsFullComposite |= pFrameInfo->useFSRLayer0; + bNeedsFullComposite |= pFrameInfo->useNISLayer0; +- bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; ++ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; + bNeedsFullComposite |= pFrameInfo->blurLayer0; + bNeedsFullComposite |= bNeedsCompositeFromFilter; + bNeedsFullComposite |= g_bColorSliderInUse; + +From 514c7c243730e6f4cae719cd5a662bc5ee68dc6c Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 00:43:10 -0300 +Subject: [PATCH 4/9] Fix black screen on bicubic filter + +--- + src/shaders/cs_bicubic.comp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shaders/cs_bicubic.comp b/src/shaders/cs_bicubic.comp +index 4904433b5..2b6dfb824 100644 +--- a/src/shaders/cs_bicubic.comp ++++ b/src/shaders/cs_bicubic.comp +@@ -8,6 +8,7 @@ + + #extension GL_GOOGLE_include_directive : require + #extension GL_EXT_shader_explicit_arithmetic_types_float16 : require ++#extension GL_EXT_scalar_block_layout : require + + #include "descriptor_set.h" + +@@ -18,7 +19,7 @@ layout( + + // Push constant is a mechanism in modern OpenGL that allows passing small amounts of frequently + // updated data to the shader without needing to bind a buffer +-layout(push_constant) ++layout(binding = 0, scalar) + uniform layers_t { + uvec4 c0, c1; + }; + +From 8fa17e48fa07210f03d2643f3fe8811e2e6aa9a4 Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 01:27:35 -0300 +Subject: [PATCH 5/9] Use bicubic as an option of --filter + +--- + src/main.cpp | 39 ++++++++++++++++++++++++++++++++------- + 1 file changed, 32 insertions(+), 7 deletions(-) + +diff --git a/src/main.cpp b/src/main.cpp +index de25ddeab..b7f5985b9 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -64,7 +64,6 @@ const struct option *gamescope_options = (struct option[]){ + { "output-height", required_argument, nullptr, 'H' }, + { "sharpness", required_argument, nullptr, 0 }, + { "fsr-sharpness", required_argument, nullptr, 0 }, +- { "bicubic", optional_argument, nullptr, 'D' }, + { "rt", no_argument, nullptr, 0 }, + { "prefer-vk-device", required_argument, 0 }, + { "expose-wayland", no_argument, 0 }, +@@ -404,8 +403,26 @@ static enum GamescopeUpscaleFilter parse_upscaler_filter(const char *str) + + static enum GamescopeDownscaleFilter parse_downscaler_filter(const char *str) + { +- std::stringstream ss{optarg}; ++ std::string_view arg{str}; + ++ // If the string is just 'bicubic' use default values ++ if ( arg == "bicubic" ) { ++ return GamescopeDownscaleFilter::BICUBIC; ++ } ++ ++ // Arguments start after ':' ++ if ( auto search = arg.find(':'); search == std::string::npos ) { ++ fprintf( stderr, "gamescope: invalid argument for --filter=bicubic:float,float\n" ); ++ exit(1); ++ } else { ++ arg = std::string_view(arg.data() + search + 1); ++ } ++ ++ // Push arguments to stream ++ std::stringstream ss; ++ ss << arg; ++ ++ // Validate arguments from stream + double b, c; + char comma; + if ((ss >> b >> comma >> c) && (comma == ',')) { +@@ -419,10 +436,21 @@ static enum GamescopeDownscaleFilter parse_downscaler_filter(const char *str) + return GamescopeDownscaleFilter::BICUBIC; + } + +- fprintf( stderr, "gamescope: invalid value for --bicubic\n" ); ++ fprintf( stderr, "gamescope: invalid value for --filter\n" ); + exit(1); + } + ++static void parse_filter(const char *str) ++{ ++ fprintf(stderr, "str: %s\n", str); ++ if (std::string_view{str}.starts_with("bicubic")) { ++ fprintf(stderr, "Startswith\n"); ++ g_wantedDownscaleFilter = parse_downscaler_filter(str); ++ } else { ++ g_wantedUpscaleFilter = parse_upscaler_filter(str); ++ } ++} ++ + static enum gamescope::GamescopeBackend parse_backend_name(const char *str) + { + if (strcmp(str, "auto") == 0) { +@@ -728,10 +756,7 @@ int main(int argc, char **argv) + g_wantedUpscaleScaler = parse_upscaler_scaler(optarg); + break; + case 'F': +- g_wantedUpscaleFilter = parse_upscaler_filter(optarg); +- break; +- case 'D': +- g_wantedDownscaleFilter = parse_downscaler_filter(optarg); ++ parse_filter(optarg); + break; + case 'b': + g_bBorderlessOutputWindow = true; + +From 5e50b2f931abe251e656138ba7bd0e5694dcc671 Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 01:44:06 -0300 +Subject: [PATCH 6/9] Updated README with bicubic info + +--- + README.md | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/README.md b/README.md +index 8aa0227bf..cfae48017 100644 +--- a/README.md ++++ b/README.md +@@ -66,6 +66,7 @@ See `gamescope --help` for a full list of options. + * `-o`: set a frame-rate limit for the game when unfocused. Specified in frames per second. Defaults to unlimited. + * `-F fsr`: use AMD FidelityFX™ Super Resolution 1.0 for upscaling + * `-F nis`: use NVIDIA Image Scaling v1.0.3 for upscaling ++* `-F bicubic`: use a bicubic filter for downscaling + * `-S integer`: use integer scaling. + * `-S stretch`: use stretch scaling, the game will fill the window. (e.g. 4:3 to 16:9) + * `-b`: create a border-less window. + +From c1832fc5a44df8fc4c30c47b45638694e51bfa53 Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 01:45:55 -0300 +Subject: [PATCH 7/9] Fix indentation in meson.build + +--- + src/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/meson.build b/src/meson.build +index 907277a23..90096979a 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -66,7 +66,7 @@ shader_src = [ + 'shaders/cs_composite_rcas.comp', + 'shaders/cs_easu.comp', + 'shaders/cs_easu_fp16.comp', +- 'shaders/cs_bicubic.comp', ++ 'shaders/cs_bicubic.comp', + 'shaders/cs_gaussian_blur_horizontal.comp', + 'shaders/cs_nis.comp', + 'shaders/cs_nis_fp16.comp', + +From 7ad3fc2a5e0ce35758fec6a8fb51fb4306cbc6e1 Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 05:31:33 -0300 +Subject: [PATCH 8/9] Remove debug print + +--- + src/main.cpp | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/main.cpp b/src/main.cpp +index b7f5985b9..32a20cbd5 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -442,9 +442,7 @@ static enum GamescopeDownscaleFilter parse_downscaler_filter(const char *str) + + static void parse_filter(const char *str) + { +- fprintf(stderr, "str: %s\n", str); + if (std::string_view{str}.starts_with("bicubic")) { +- fprintf(stderr, "Startswith\n"); + g_wantedDownscaleFilter = parse_downscaler_filter(str); + } else { + g_wantedUpscaleFilter = parse_upscaler_filter(str); + +From 6649fd8f0e7d2bce465855221f30eafc06f9a4ce Mon Sep 17 00:00:00 2001 +From: "Ruan E. Formigoni" +Date: Mon, 7 Oct 2024 05:34:15 -0300 +Subject: [PATCH 9/9] Remove outdated comments + +--- + src/rendervulkan.cpp | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp +index e80afb68a..33f999101 100644 +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -3917,7 +3917,6 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco + + if ( frameInfo->useBICUBICLayer0 ) + { +- // fprintf(stderr, "-- Use bicubic\n"); + uint32_t inputX = frameInfo->layers[0].tex->width(); + uint32_t inputY = frameInfo->layers[0].tex->height(); + +@@ -3927,7 +3926,6 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco + update_tmp_images(tempX, tempY); + + cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BICUBIC, frameInfo->layerCount, frameInfo->ycbcrMask())); +- // cmdBuffer->bindTarget(compositeImage); + cmdBuffer->bindTarget(g_output.tmpOutput); + cmdBuffer->bindTexture(0, frameInfo->layers[0].tex); + cmdBuffer->setTextureSrgb(0, true); diff --git a/spec_files/gamescope/ally-display.patch b/spec_files/gamescope/ally-display.patch new file mode 100644 index 00000000..44ada7cb --- /dev/null +++ b/spec_files/gamescope/ally-display.patch @@ -0,0 +1,101 @@ +From b288a82a61005b91dd268b8ea4e8d124d4dd5267 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Mon, 7 Oct 2024 16:45:49 -0700 +Subject: [PATCH] script: ASUS ROG Ally + ROG Ally X display configuration + +This introduces a display configuration for the ROG Ally and +ROG Ally X handhelds. These devices feature the same 1920x1080p panel, +which supports VRR and has a range limit of 48-120Hz in the EDID. + +I tested this configuration on two separate units: +* ROG Ally - SteamOS Main 20240919.1002 with kernel 6.8.12-valve2-1 +* ROG Ally X - SteamOS Main 20240919.1002 with kernel 6.11.2 + +Both function exactly the same throughout multiple games with the +entire refresh rate slider within Steam. + +Signed-off-by: Matthew Schwartz +--- + .../displays/asus.rogally.lcd.lua | 73 +++++++++++++++++++ + 1 file changed, 73 insertions(+) + create mode 100644 scripts/00-gamescope/displays/asus.rogally.lcd.lua + +diff --git a/scripts/00-gamescope/displays/asus.rogally.lcd.lua b/scripts/00-gamescope/displays/asus.rogally.lcd.lua +new file mode 100644 +index 000000000..483f41037 +--- /dev/null ++++ b/scripts/00-gamescope/displays/asus.rogally.lcd.lua +@@ -0,0 +1,73 @@ ++local rogally_lcd_refresh_rates = { ++ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, ++ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, ++ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, ++ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, ++ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, ++ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, ++ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, ++ 118, 119, 120 ++} ++ ++gamescope.config.known_displays.rogally_lcd = { ++ pretty_name = "ROG Ally/Ally X LCD", ++ hdr = { ++ -- Setup some fallbacks for undocking with HDR, meant ++ -- for the internal panel. It does not support HDR. ++ supported = false, ++ force_enabled = false, ++ eotf = gamescope.eotf.gamma22, ++ max_content_light_level = 500, ++ max_frame_average_luminance = 500, ++ min_content_light_level = 0.5 ++ }, ++ -- Use the EDID colorimetry for now, but someone may ++ -- be able to tune this better for gamescope. ++ dynamic_refresh_rates = rogally_lcd_refresh_rates, ++ -- Follow the Steam Deck OLED style for modegen ++ -- and VFPs given framebuffer capabilities. ++ dynamic_modegen = function(base_mode, refresh) ++ debug("Generating mode "..refresh.."Hz for ROG Ally with fixed pixel clock") ++ local vfps = { ++ 1771, 1720, 1655, 1600, 1549, ++ 1499, 1455, 1405, 1361, 1320, ++ 1279, 1224, 1200, 1162, 1120, ++ 1088, 1055, 1022, 991, 958, ++ 930, 900, 871, 845, 817, ++ 794, 762, 740, 715, 690, ++ 668, 647, 626, 605, 585, ++ 566, 546, 526, 507, 488, ++ 470, 452, 435, 419, 402, ++ 387, 371, 355, 341, 326, ++ 310, 297, 284, 269, 255, ++ 244, 229, 217, 204, 194, ++ 181, 172, 158, 147, 136, ++ 123, 113, 104, 93, 83, ++ 74, 64, 54 ++ } ++ local vfp = vfps[zero_index(refresh - 48)] ++ if vfp == nil then ++ warn("Couldn't do refresh "..refresh.." on ROG Ally") ++ return base_mode ++ end ++ ++ local mode = base_mode ++ ++ gamescope.modegen.adjust_front_porch(mode, vfp) ++ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) ++ ++ --debug(inspect(mode)) ++ return mode ++ end, ++ -- There is only a single panel model in use across both ++ -- ROG Ally + ROG Ally X. ++ matches = function(display) ++ if display.vendor == "TMX" and display.model == "TL070FVXS01-0" and display.product == 0x0002 then ++ debug("[rogally_lcd] Matched vendor: "..value.vendor.." model: "..value.model.." product:"..value.product) ++ return 5000 ++ end ++ return -1 ++ end ++} ++ debug("Registered ROG Ally/Ally X LCD as a known display") ++ --debug(inspect(gamescope.config.known_displays.rogally_lcd)) diff --git a/spec_files/gamescope/gamescope.spec b/spec_files/gamescope/gamescope.spec index e523b35c..f8d7c512 100644 --- a/spec_files/gamescope/gamescope.spec +++ b/spec_files/gamescope/gamescope.spec @@ -6,7 +6,7 @@ Name: gamescope Version: 100.%{gamescope_tag} -Release: 3.bazzite +Release: 4.bazzite Summary: Micro-compositor for video games on Wayland License: BSD @@ -30,6 +30,12 @@ Patch4: revert-299bc34.patch # https://github.com/ValveSoftware/gamescope/pull/1231 Patch5: 1231.patch +# https://github.com/ValveSoftware/gamescope/commit/b288a82a61005b91dd268b8ea4e8d124d4dd5267 +Patch6: ally-display.patch + +# https://github.com/ValveSoftware/gamescope/pull/740 +Patch7: 740.patch + BuildRequires: meson >= 0.54.0 BuildRequires: ninja-build BuildRequires: cmake