From 08d9dec76f50144bdac6efa29c1ecfe2e1bdfb1c Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 20 Oct 2022 06:52:28 +0000 Subject: [PATCH 01/28] Added controller rumble support. Pepper SDK and NaCl in general is EOL for Chrome, although still supported for Chrome Apps. This means that the Pepper Gamepad API was never updated with rumble support so in order to add rumble support, rumble messages from Gamestream have to be forwarded to JavaScript and handled with gamepad.vibrationActuator.playEffect(). Side note, Chrome limits the duration of playEffect to 5 seconds and requesting more than that causes the vibration request to be rejected. --- connectionlistener.cpp | 1 + gamepad.cpp | 13 +++++++++++++ manifest.json | 2 +- moonlight.hpp | 1 + static/js/messages.js | 12 ++++++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/connectionlistener.cpp b/connectionlistener.cpp index 094081f1..bfc79f86 100644 --- a/connectionlistener.cpp +++ b/connectionlistener.cpp @@ -56,4 +56,5 @@ CONNECTION_LISTENER_CALLBACKS MoonlightInstance::s_ClCallbacks = { .connectionStarted = MoonlightInstance::ClConnectionStarted, .connectionTerminated = MoonlightInstance::ClConnectionTerminated, .logMessage = MoonlightInstance::ClLogMessage, + .rumble = MoonlightInstance::ClControllerRumble, }; diff --git a/gamepad.cpp b/gamepad.cpp index 93df0fca..eac6979a 100644 --- a/gamepad.cpp +++ b/gamepad.cpp @@ -4,6 +4,8 @@ #include +#include + static const unsigned short k_StandardGamepadButtonMapping[] = { A_FLAG, B_FLAG, X_FLAG, Y_FLAG, LB_FLAG, RB_FLAG, @@ -127,3 +129,14 @@ void MoonlightInstance::PollGamepads() { controllerIndex++; } } + +void MoonlightInstance::ClControllerRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor) +{ + const float weakMagnitude = static_cast(highFreqMotor) / static_cast(UINT16_MAX); + const float strongMagnitude = static_cast(lowFreqMotor) / static_cast(UINT16_MAX); + + std::ostringstream ss; + ss << controllerNumber << "," << weakMagnitude << "," << strongMagnitude; + pp::Var response(std::string("controllerRumble: ") + ss.str()); + g_Instance->PostMessage(response); +} \ No newline at end of file diff --git a/manifest.json b/manifest.json index ac1aef25..2a509bbb 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "Moonlight Game Streaming", "short_name": "Moonlight", - "version": "0.10.21", + "version": "0.10.22", "description": "Open-source client for NVIDIA GameStream", "icons": { "128": "icons/icon128.png", diff --git a/moonlight.hpp b/moonlight.hpp index 452aad64..56a70fbd 100644 --- a/moonlight.hpp +++ b/moonlight.hpp @@ -137,6 +137,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { static void ClDisplayMessage(const char* message); static void ClDisplayTransientMessage(const char* message); static void ClLogMessage(const char* format, ...); + static void ClControllerRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor); static Shader CreateProgram(const char* vertexShader, const char* fragmentShader); static void CreateShader(GLuint program, GLenum type, const char* source, int size); diff --git a/static/js/messages.js b/static/js/messages.js index d8ab820b..3a0970dc 100644 --- a/static/js/messages.js +++ b/static/js/messages.js @@ -81,6 +81,18 @@ function handleMessage(msg) { snackbarLogLong(msg.data.replace('DialogMsg: ', '')); } else if (msg.data === 'displayVideo') { $("#listener").addClass("fullscreen"); + } else if (msg.data.indexOf('controllerRumble: ' ) === 0) { + const eventData = msg.data.split( ' ' )[1].split(','); + const gamepadIdx = parseInt(eventData[0]); + const weakMagnitude = parseFloat(eventData[1]); + const strongMagnitude = parseFloat(eventData[2]); + console.log("Playing rumble on gamepad " + gamepadIdx + " with weakMagnitude " + weakMagnitude + " and strongMagnitude " + strongMagnitude); + navigator.getGamepads()[gamepadIdx].vibrationActuator.playEffect('dual-rumble', { + startDelay: 0, + duration: 5000, // Moonlight should be sending another rumble event when stopping. + weakMagnitude: weakMagnitude, + strongMagnitude: strongMagnitude, + }); } } } From 06100217d6054f4bd617c3ea2dda5f7d08f090c5 Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sat, 22 Oct 2022 15:05:04 -0700 Subject: [PATCH 02/28] Remove explicit fullscreen handling Moonlight's fullscreen requests generally conflict with what ChromeOS is trying to do automatically for the app, especially when using tablet mode. Just remove it for now and let the OS handle fullscreen. --- manifest.json | 3 +-- static/js/background.js | 17 +++---------- static/js/index.js | 53 ----------------------------------------- 3 files changed, 4 insertions(+), 69 deletions(-) diff --git a/manifest.json b/manifest.json index 2a509bbb..f4b9759c 100644 --- a/manifest.json +++ b/manifest.json @@ -26,8 +26,7 @@ "pointerLock", "system.network", "fullscreen", - "power", - "overrideEscFullscreen", { + "power", { "socket": [ "tcp-connect", "resolve-host", diff --git a/static/js/background.js b/static/js/background.js index 664eb98e..65f2de33 100644 --- a/static/js/background.js +++ b/static/js/background.js @@ -1,19 +1,8 @@ +const windowId = "1337"; function createWindow(state) { chrome.app.window.create('index.html', { - state: state, - bounds: { - width: 960, - height: 540 - } - }, function(window) { - // workaround: - // state = 'normal' in some cases not work (e.g. starting app from 'chrome://extensions' always open window in fullscreen mode) - // it requires manually restoring window state to 'normal' - if (state == 'normal') { - setTimeout(function() { - window.restore(); - }, 1000); - } + state: "normal", + id: windowId, }); } diff --git a/static/js/index.js b/static/js/index.js index 08408250..13276b8d 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -4,7 +4,6 @@ var pairingCert; var myUniqueid = '0123456789ABCDEF'; // Use the same UID as other Moonlight clients to allow them to quit each other's games var api; // `api` should only be set if we're in a host-specific screen. on the initial screen it should always be null. var isInGame = false; // flag indicating whether the game stream started -var windowState = 'normal'; // chrome's windowState, possible values: 'normal' or 'fullscreen' // Called by the common.js module. function attachListeners() { @@ -21,49 +20,6 @@ function attachListeners() { $('#backIcon').on('click', showHostsAndSettingsMode); $('#quitCurrentApp').on('click', stopGameWithConfirmation); $(window).resize(fullscreenNaclModule); - chrome.app.window.current().onMaximized.addListener(fullscreenChromeWindow); -} - -function fullscreenChromeWindow() { - // when the user clicks the maximize button on the window, - // FIRST restore it to the previous size, then fullscreen it to the whole screen - // this prevents the previous window size from being 'maximized', - // and allows us to functionally retain two window sizes - // so that when the user hits `esc`, they go back to the "restored" size, - // instead of "maximized", which would immediately go to fullscreen - chrome.app.window.current().restore(); - chrome.app.window.current().fullscreen(); -} - -function loadWindowState() { - if (!chrome.storage) { - return; - } - - chrome.storage.sync.get('windowState', function(item) { - // load stored window state - windowState = (item && item.windowState) ? - item.windowState : - windowState; - - // subscribe to chrome's windowState events - chrome.app.window.current().onFullscreened.addListener(onFullscreened); - chrome.app.window.current().onBoundsChanged.addListener(onBoundsChanged); - }); -} - -function onFullscreened() { - if (!isInGame && windowState == 'normal') { - storeData('windowState', 'fullscreen', null); - windowState = 'fullscreen'; - } -} - -function onBoundsChanged() { - if (!isInGame && windowState == 'fullscreen') { - storeData('windowState', 'normal', null); - windowState = 'normal'; - } } function changeUiModeForNaClLoad() { @@ -625,11 +581,6 @@ function showAppsMode() { $('#loadingSpinner').css('display', 'none'); $('body').css('backgroundColor', '#282C38'); - // Restore back to a window - if (windowState == 'normal') { - chrome.app.window.current().restore(); - } - isInGame = false; // FIXME: We want to eventually poll on the app screen but we can't now @@ -768,10 +719,8 @@ function playGameMode() { $("#main-content").children().not("#listener, #loadingSpinner").hide(); $("#main-content").addClass("fullscreen"); - chrome.app.window.current().fullscreen(); fullscreenNaclModule(); $('#loadingSpinner').css('display', 'inline-block'); - } // Maximize the size of the nacl module by scaling and resizing appropriately @@ -950,8 +899,6 @@ function onWindowLoad() { // don't show the game selection div $('#gameSelection').css('display', 'none'); - loadWindowState(); - if (chrome.storage) { // load stored resolution prefs chrome.storage.sync.get('resolution', function(previousValue) { From 627494ed3c95580fec1b3077cd6723e59354f405 Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sat, 22 Oct 2022 15:34:56 -0700 Subject: [PATCH 03/28] Restore overrideEscFullscreen permission Otherwise, Esc breaks out of fullscreen instead of being sent to the streaming app. --- manifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index f4b9759c..2a509bbb 100644 --- a/manifest.json +++ b/manifest.json @@ -26,7 +26,8 @@ "pointerLock", "system.network", "fullscreen", - "power", { + "power", + "overrideEscFullscreen", { "socket": [ "tcp-connect", "resolve-host", From b88decd31fc820d35ba5f5f4a13e2817de7ec8fd Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sat, 22 Oct 2022 15:55:32 -0700 Subject: [PATCH 04/28] Fix black screen when starting game stream Adding fullscreen class to the #listener seems to fix the game stream getting stuck in a black screen. I suspect that #main-content isn't recomputing its layout when #listener is resized. --- static/js/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/js/index.js b/static/js/index.js index 13276b8d..c593308c 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -718,6 +718,7 @@ function playGameMode() { $("#main-navigation").hide(); $("#main-content").children().not("#listener, #loadingSpinner").hide(); $("#main-content").addClass("fullscreen"); + $("#listener").addClass("fullscreen"); fullscreenNaclModule(); $('#loadingSpinner').css('display', 'inline-block'); From d584fa998c22d8e99a680359d1945c634a6c0c97 Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sun, 23 Oct 2022 03:29:27 +0000 Subject: [PATCH 05/28] Updated Video Decode Shader with black crush mitigation logic Shader is compiling successfully, but the required data not yet hooked up. --- viddec.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/viddec.cpp b/viddec.cpp index 7993b244..a3c07918 100644 --- a/viddec.cpp +++ b/viddec.cpp @@ -18,6 +18,32 @@ static uint64_t s_LastPaintFinishedTime; #define assertNoGLError() assert(!glGetError()) +// Assume gl_FragColor is in sRGB space and do a poor approximate conversion to linear. +// After conversion to XYZ space, curve the Y value up to brighten dark values and +// then convert back to sRGB. +#define fragmentShader_BlackCrushMitigation() \ + "const vec3 CIE_X_FROM_RGB_WEIGHTS = vec3(0.4124f, 0.3576f, 0.1805f); \n" \ + "const vec3 CIE_Y_FROM_RGB_WEIGHTS = vec3(0.2126f, 0.7152f, 0.0722f); \n" \ + "const vec3 CIE_Z_FROM_RGB_WEIGHTS = vec3(0.0193f, 0.1192f, 0.9505f); \n" \ + "const vec3 R_FROM_CIEXYZ_WEIGHTS = vec3(3.2406f, -1.5372f, -0.4986f); \n" \ + "const vec3 G_FROM_CIEXYZ_WEIGHTS = vec3(-0.9689f, 1.8758f, 0.0415f); \n" \ + "const vec3 B_FROM_CIEXYZ_WEIGHTS = vec3(0.0557f, -0.2040f, 1.0570f); \n" \ + "const float TEXEL_WIDTH_HEIGHT = 0.0625f; \n" \ + "const float CURVE_TEXTURE_WIDTH = 16.0f; \n" \ + "const float CURVE_TEXTURE_HEIGHT = 16.0f; \n" \ + "vec3 linearRGB = texColor.rgb * texColor.rgb; \n" \ + "float cieX = dot(CIE_X_FROM_RGB_WEIGHTS, linearRGB); \n" \ + "float cieY = dot(CIE_Y_FROM_RGB_WEIGHTS, linearRGB); \n" \ + "float cieZ = dot(CIE_Z_FROM_RGB_WEIGHTS, linearRGB); \n" \ + "float curveTexCoord1D = cieY * (CURVE_TEXTURE_WIDTH * CURVE_TEXTURE_HEIGHT - 1.0f); \n" \ + "float curveTexCoord2DRowIdx = floor(curveTexCoord1D / CURVE_TEXTURE_WIDTH); \n" \ + "float curveTexCoord2DSubRowIdx = (curveTexCoord1D - curveTexCoord2DRowIdx * CURVE_TEXTURE_WIDTH); \n" \ + "vec2 curveTexCoord2D = vec2((curveTexCoord2DSubRowIdx + 0.5f) * TEXEL_WIDTH_HEIGHT, (curveTexCoord2DRowIdx + 0.5f) * TEXEL_WIDTH_HEIGHT); \n" \ + "float cieYCurved = texture2D(s_curveTexture, curveTexCoord2D).a; \n" \ + "vec3 cieXYZCurved = vec3(cieX, cieYCurved, cieZ); \n" \ + "vec3 linearRGBCurved = vec3(dot(R_FROM_CIEXYZ_WEIGHTS, cieXYZCurved), dot(G_FROM_CIEXYZ_WEIGHTS, cieXYZCurved), dot(B_FROM_CIEXYZ_WEIGHTS, cieXYZCurved)); \n" \ + "gl_FragColor.rgb = sqrt(linearRGBCurved);" + static const char k_VertexShader[] = "varying vec2 v_texCoord; \n" "attribute vec4 a_position; \n" @@ -33,9 +59,12 @@ static const char k_FragmentShader2D[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform sampler2D s_texture; \n" + "uniform sampler2D s_curveTexture; \n" "void main() \n" "{" - " gl_FragColor = texture2D(s_texture, v_texCoord); \n" + " vec4 texColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor = texColor; \n" + fragmentShader_BlackCrushMitigation() "}"; static const char k_FragmentShaderRectangle[] = @@ -43,9 +72,12 @@ static const char k_FragmentShaderRectangle[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform sampler2DRect s_texture; \n" + "uniform sampler2D s_curveTexture; \n" "void main() \n" "{" - " gl_FragColor = texture2DRect(s_texture, v_texCoord).rgba; \n" + " vec4 texColor = texture2DRect(s_texture, v_texCoord).rgba; \n" + " gl_FragColor = texColor; \n" + fragmentShader_BlackCrushMitigation() "}"; static const char k_FragmentShaderExternal[] = @@ -53,9 +85,12 @@ static const char k_FragmentShaderExternal[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform samplerExternalOES s_texture; \n" + "uniform sampler2D s_curveTexture; \n" "void main() \n" "{" - " gl_FragColor = texture2D(s_texture, v_texCoord); \n" + " vec4 texColor = texture2D(s_texture, v_texCoord); \n" + " gl_FragColor = texColor; \n" + fragmentShader_BlackCrushMitigation() "}"; void MoonlightInstance::DidChangeFocus(bool got_focus) { From 291797f7caf6aa410848499295b209cfb09775e6 Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sun, 23 Oct 2022 05:32:37 +0000 Subject: [PATCH 06/28] More progress with shaders A lot of plumbing is set up but Chrome seems sensitive to certain OGL calls hanging the NaCl module. I don't understand what's happening but this is version at least draws the video stream again, even if it's messed up. --- moonlight.hpp | 4 +++ viddec.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 90 insertions(+), 12 deletions(-) diff --git a/moonlight.hpp b/moonlight.hpp index 56a70fbd..d0ea311f 100644 --- a/moonlight.hpp +++ b/moonlight.hpp @@ -56,6 +56,8 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { explicit MoonlightInstance(PP_Instance instance) : pp::Instance(instance), pp::MouseLock(this), + m_BlackCrushMitigationEnable(false), + m_curveTexture(-1u), m_HasNextPicture(false), m_IsPainting(false), m_OpusDecoder(NULL), @@ -187,6 +189,8 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { Shader m_RectangleArbShader; Shader m_ExternalOesShader; PP_VideoPicture m_NextPicture; + bool m_BlackCrushMitigationEnable; + GLuint m_curveTexture; bool m_HasNextPicture; PP_VideoPicture m_CurrentPicture; bool m_IsPainting; diff --git a/viddec.cpp b/viddec.cpp index a3c07918..ed56990e 100644 --- a/viddec.cpp +++ b/viddec.cpp @@ -22,27 +22,27 @@ static uint64_t s_LastPaintFinishedTime; // After conversion to XYZ space, curve the Y value up to brighten dark values and // then convert back to sRGB. #define fragmentShader_BlackCrushMitigation() \ - "const vec3 CIE_X_FROM_RGB_WEIGHTS = vec3(0.4124f, 0.3576f, 0.1805f); \n" \ - "const vec3 CIE_Y_FROM_RGB_WEIGHTS = vec3(0.2126f, 0.7152f, 0.0722f); \n" \ - "const vec3 CIE_Z_FROM_RGB_WEIGHTS = vec3(0.0193f, 0.1192f, 0.9505f); \n" \ - "const vec3 R_FROM_CIEXYZ_WEIGHTS = vec3(3.2406f, -1.5372f, -0.4986f); \n" \ - "const vec3 G_FROM_CIEXYZ_WEIGHTS = vec3(-0.9689f, 1.8758f, 0.0415f); \n" \ - "const vec3 B_FROM_CIEXYZ_WEIGHTS = vec3(0.0557f, -0.2040f, 1.0570f); \n" \ - "const float TEXEL_WIDTH_HEIGHT = 0.0625f; \n" \ - "const float CURVE_TEXTURE_WIDTH = 16.0f; \n" \ - "const float CURVE_TEXTURE_HEIGHT = 16.0f; \n" \ + "vec3 CIE_X_FROM_RGB_WEIGHTS = vec3(0.4124, 0.3576, 0.1805); \n" \ + "vec3 CIE_Y_FROM_RGB_WEIGHTS = vec3(0.2126, 0.7152, 0.0722); \n" \ + "vec3 CIE_Z_FROM_RGB_WEIGHTS = vec3(0.0193, 0.1192, 0.9505); \n" \ + "vec3 R_FROM_CIEXYZ_WEIGHTS = vec3(3.2406, -1.5372, -0.4986); \n" \ + "vec3 G_FROM_CIEXYZ_WEIGHTS = vec3(-0.9689, 1.8758, 0.0415); \n" \ + "vec3 B_FROM_CIEXYZ_WEIGHTS = vec3(0.0557, -0.2040, 1.0570); \n" \ + "float TEXEL_WIDTH_HEIGHT = 0.0625; \n" \ + "float CURVE_TEXTURE_WIDTH = 16.0; \n" \ + "float CURVE_TEXTURE_HEIGHT = 16.0; \n" \ "vec3 linearRGB = texColor.rgb * texColor.rgb; \n" \ "float cieX = dot(CIE_X_FROM_RGB_WEIGHTS, linearRGB); \n" \ "float cieY = dot(CIE_Y_FROM_RGB_WEIGHTS, linearRGB); \n" \ "float cieZ = dot(CIE_Z_FROM_RGB_WEIGHTS, linearRGB); \n" \ - "float curveTexCoord1D = cieY * (CURVE_TEXTURE_WIDTH * CURVE_TEXTURE_HEIGHT - 1.0f); \n" \ + "float curveTexCoord1D = cieY * (CURVE_TEXTURE_WIDTH * CURVE_TEXTURE_HEIGHT - 1.0); \n" \ "float curveTexCoord2DRowIdx = floor(curveTexCoord1D / CURVE_TEXTURE_WIDTH); \n" \ "float curveTexCoord2DSubRowIdx = (curveTexCoord1D - curveTexCoord2DRowIdx * CURVE_TEXTURE_WIDTH); \n" \ - "vec2 curveTexCoord2D = vec2((curveTexCoord2DSubRowIdx + 0.5f) * TEXEL_WIDTH_HEIGHT, (curveTexCoord2DRowIdx + 0.5f) * TEXEL_WIDTH_HEIGHT); \n" \ + "vec2 curveTexCoord2D = vec2((curveTexCoord2DSubRowIdx + 0.5) * TEXEL_WIDTH_HEIGHT, (curveTexCoord2DRowIdx + 0.5) * TEXEL_WIDTH_HEIGHT); \n" \ "float cieYCurved = texture2D(s_curveTexture, curveTexCoord2D).a; \n" \ "vec3 cieXYZCurved = vec3(cieX, cieYCurved, cieZ); \n" \ "vec3 linearRGBCurved = vec3(dot(R_FROM_CIEXYZ_WEIGHTS, cieXYZCurved), dot(G_FROM_CIEXYZ_WEIGHTS, cieXYZCurved), dot(B_FROM_CIEXYZ_WEIGHTS, cieXYZCurved)); \n" \ - "gl_FragColor.rgb = sqrt(linearRGBCurved);" + "gl_FragColor = vec4(sqrt(linearRGBCurved), texColor.a);" static const char k_VertexShader[] = "varying vec2 v_texCoord; \n" @@ -93,6 +93,47 @@ static const char k_FragmentShaderExternal[] = fragmentShader_BlackCrushMitigation() "}"; + +static const unsigned char k_BlackCrushMitigationCurve[] = +{ + 0,4,6,8,10,11,12,13,14,15,16,17,18,19,20,21, + 22,23,24,24,25,25,26,26,27,27,28,28,29,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 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,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const unsigned char k_IdentityCurve[] = +{ + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 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,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + void MoonlightInstance::DidChangeFocus(bool got_focus) { // Request an IDR frame to dump the frame queue that may have // built up from the GL pipeline being stalled. @@ -109,6 +150,8 @@ bool MoonlightInstance::InitializeRenderingSurface(int width, int height) { if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { return false; } + + g_Instance->PostMessage(pp::Var("Initializing rendering surface.")); int32_t contextAttributes[] = { PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, @@ -167,6 +210,21 @@ bool MoonlightInstance::InitializeRenderingSurface(int width, int height) { k_Vertices, GL_STATIC_DRAW); assertNoGLError(); + + if (m_curveTexture != -1u) + glDeleteTextures(1, &m_curveTexture); + glGenTextures(1, &m_curveTexture); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_curveTexture); + + GLint existingUnpackAlignment; + glGetIntegerv(GL_UNPACK_ALIGNMENT, &existingUnpackAlignment); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, m_BlackCrushMitigationEnable ? k_BlackCrushMitigationCurve : k_IdentityCurve); + glPixelStorei(GL_UNPACK_ALIGNMENT, existingUnpackAlignment); + + glActiveTexture(GL_TEXTURE0); g_Instance->m_Graphics3D.SwapBuffers(pp::BlockUntilComplete()); return true; @@ -324,6 +382,21 @@ void MoonlightInstance::CreateShader(GLuint program, GLenum type, GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, &size); glCompileShader(shader); + + GLint compileSuccess; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess); + if (type == GL_FRAGMENT_SHADER && compileSuccess == GL_FALSE) + { + pp::Var response(std::string("Compile shader: \n") + source); + g_Instance->PostMessage(response); + + GLchar compileInfoLog[2048]; + GLsizei actualInfoLogLength; + glGetShaderInfoLog(shader, 2048, &actualInfoLogLength, compileInfoLog); + response = compileInfoLog; + g_Instance->PostMessage(response); + } + glAttachShader(program, shader); glDeleteShader(shader); } @@ -338,6 +411,7 @@ Shader MoonlightInstance::CreateProgram(const char* vertexShader, const char* fr glUseProgram(shader.program); glUniform1i(glGetUniformLocation(shader.program, "s_texture"), 0); + glUniform1i(glGetUniformLocation(shader.program, "s_curveTexture"), 1); assertNoGLError(); shader.texcoord_scale_location = glGetUniformLocation(shader.program, "v_scale"); From 411dcd2770a7e6d20ac3cce7f2d0b573d282d4d1 Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sun, 23 Oct 2022 05:52:43 +0000 Subject: [PATCH 07/28] Black crush mitigation disabled now works. Finally back to a no-op equivalent state. --- viddec.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/viddec.cpp b/viddec.cpp index ed56990e..33b52f56 100644 --- a/viddec.cpp +++ b/viddec.cpp @@ -218,6 +218,11 @@ bool MoonlightInstance::InitializeRenderingSurface(int width, int height) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, m_curveTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + GLint existingUnpackAlignment; glGetIntegerv(GL_UNPACK_ALIGNMENT, &existingUnpackAlignment); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -482,8 +487,12 @@ void MoonlightInstance::PaintPicture(void) { // Only rebind our texture if we've changed since last time if (m_CurrentPicture.texture_id != s_LastTextureId || m_CurrentPicture.texture_target != originalTextureTarget) { + glActiveTexture(GL_TEXTURE0); glBindTexture(m_CurrentPicture.texture_target, m_CurrentPicture.texture_id); s_LastTextureId = m_CurrentPicture.texture_id; + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_curveTexture); } // Draw the image From 1a0de99e25f3e6a1f80fcbf531e6632c245b5b8b Mon Sep 17 00:00:00 2001 From: utopiafallen Date: Sun, 23 Oct 2022 06:08:16 +0000 Subject: [PATCH 08/28] Hookup black crush mitigation to UI --- index.html | 10 ++++++++++ main.cpp | 6 ++++-- static/js/index.js | 28 +++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 36c5953f..9ca43aff 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,16 @@ + +