Decouple renderer from decoder and remove associated workarounds

This commit is contained in:
Cameron Gutman 2016-05-05 16:57:26 -04:00
parent 25062b99b1
commit 21dd55566e
3 changed files with 34 additions and 65 deletions

View File

@ -27,11 +27,6 @@ static int ConvertPPButtonToLiButton(PP_InputEvent_MouseButton ppButton) {
void MoonlightInstance::DidLockMouse(int32_t result) { void MoonlightInstance::DidLockMouse(int32_t result) {
m_MouseLocked = (result == PP_OK); m_MouseLocked = (result == PP_OK);
if (m_MouseLocked) {
// Request an IDR frame to dump the frame queue that may have
// built up from the GL pipeline being stalled.
m_RequestIdrFrame = true;
}
} }
void MoonlightInstance::MouseLockLost() { void MoonlightInstance::MouseLockLost() {

View File

@ -41,8 +41,8 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
explicit MoonlightInstance(PP_Instance instance) : explicit MoonlightInstance(PP_Instance instance) :
pp::Instance(instance), pp::Instance(instance),
pp::MouseLock(this), pp::MouseLock(this),
m_HasNextPicture(false),
m_IsPainting(false), m_IsPainting(false),
m_RequestIdrFrame(false),
m_OpusDecoder(NULL), m_OpusDecoder(NULL),
m_CallbackFactory(this), m_CallbackFactory(this),
m_MouseLocked(false), m_MouseLocked(false),
@ -81,7 +81,6 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
void MouseLockLost(); void MouseLockLost();
void DidLockMouse(int32_t result); void DidLockMouse(int32_t result);
void DidChangeFocus(bool got_focus);
void OnConnectionStopped(uint32_t unused); void OnConnectionStopped(uint32_t unused);
void OnConnectionStarted(uint32_t error); void OnConnectionStarted(uint32_t error);
@ -139,10 +138,11 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
Shader m_Texture2DShader; Shader m_Texture2DShader;
Shader m_RectangleArbShader; Shader m_RectangleArbShader;
Shader m_ExternalOesShader; Shader m_ExternalOesShader;
std::queue<PP_VideoPicture> m_PendingPictureQueue; PP_VideoPicture m_NextPicture;
bool m_HasNextPicture;
PP_VideoPicture m_CurrentPicture;
bool m_IsPainting; bool m_IsPainting;
bool m_RequestIdrFrame;
OpusMSDecoder* m_OpusDecoder; OpusMSDecoder* m_OpusDecoder;
pp::Audio m_AudioPlayer; pp::Audio m_AudioPlayer;

View File

@ -13,8 +13,6 @@ static unsigned char* s_DecodeBuffer;
static unsigned int s_DecodeBufferLength; static unsigned int s_DecodeBufferLength;
static int s_LastTextureType; static int s_LastTextureType;
static int s_LastTextureId; static int s_LastTextureId;
static int s_NextDecodeFrameNumber;
static int s_LastDisplayFrameNumber;
static unsigned char s_LastSps[256]; static unsigned char s_LastSps[256];
static unsigned char s_LastPps[256]; static unsigned char s_LastPps[256];
static unsigned int s_LastSpsLength; static unsigned int s_LastSpsLength;
@ -61,14 +59,6 @@ static const char k_FragmentShaderExternal[] =
"{" "{"
" gl_FragColor = texture2D(s_texture, v_texCoord); \n" " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
"}"; "}";
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.
if (got_focus) {
g_Instance->m_RequestIdrFrame = true;
}
}
void MoonlightInstance::InitializeRenderingSurface(int width, int height) { void MoonlightInstance::InitializeRenderingSurface(int width, int height) {
if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
@ -136,8 +126,6 @@ void MoonlightInstance::VidDecSetup(int videoFormat, int width, int height, int
s_LastTextureId = 0; s_LastTextureId = 0;
s_LastSpsLength = 0; s_LastSpsLength = 0;
s_LastPpsLength = 0; s_LastPpsLength = 0;
s_NextDecodeFrameNumber = 0;
s_LastDisplayFrameNumber = 0;
g_Instance->m_VideoDecoder->Initialize(g_Instance->m_Graphics3D, g_Instance->m_VideoDecoder->Initialize(g_Instance->m_Graphics3D,
PP_VIDEOPROFILE_H264HIGH, PP_VIDEOPROFILE_H264HIGH,
@ -206,12 +194,6 @@ int MoonlightInstance::VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
bool isPps = false; bool isPps = false;
bool isIframe = false; bool isIframe = false;
// Request an IDR frame if needed
if (g_Instance->m_RequestIdrFrame) {
g_Instance->m_RequestIdrFrame = false;
return DR_NEED_IDR;
}
// Look at the NALU type // Look at the NALU type
if (decodeUnit->bufferList->length > 5) { if (decodeUnit->bufferList->length > 5) {
switch (decodeUnit->bufferList->data[4]) { switch (decodeUnit->bufferList->data[4]) {
@ -279,7 +261,7 @@ int MoonlightInstance::VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
} }
// Start the decoding // Start the decoding
g_Instance->m_VideoDecoder->Decode(s_NextDecodeFrameNumber++, offset, s_DecodeBuffer, pp::BlockUntilComplete()); g_Instance->m_VideoDecoder->Decode(0, offset, s_DecodeBuffer, pp::BlockUntilComplete());
return DR_OK; return DR_OK;
} }
@ -324,20 +306,13 @@ Shader MoonlightInstance::CreateProgram(const char* vertexShader, const char* fr
void MoonlightInstance::PaintPicture(void) { void MoonlightInstance::PaintPicture(void) {
m_IsPainting = true; m_IsPainting = true;
// Free and skip all frames except the latest one // Take the next picture into our ownership
PP_VideoPicture picture; m_CurrentPicture = m_NextPicture;
while (m_PendingPictureQueue.size() > 1) { m_HasNextPicture = false;
picture = m_PendingPictureQueue.front();
m_PendingPictureQueue.pop();
g_Instance->m_VideoDecoder->RecyclePicture(picture);
}
picture = m_PendingPictureQueue.front();
// Recycle bogus pictures immediately // Recycle bogus pictures immediately
if (picture.texture_target == 0) { if (m_CurrentPicture.texture_target == 0) {
g_Instance->m_VideoDecoder->RecyclePicture(picture); m_VideoDecoder->RecyclePicture(m_CurrentPicture);
m_PendingPictureQueue.pop();
m_IsPainting = false; m_IsPainting = false;
return; return;
} }
@ -349,23 +324,23 @@ void MoonlightInstance::PaintPicture(void) {
int originalTextureTarget = s_LastTextureType; int originalTextureTarget = s_LastTextureType;
// Only make these state changes if we've changed from the last texture type // Only make these state changes if we've changed from the last texture type
if (picture.texture_target != s_LastTextureType) { if (m_CurrentPicture.texture_target != s_LastTextureType) {
if (picture.texture_target == GL_TEXTURE_2D) { if (m_CurrentPicture.texture_target == GL_TEXTURE_2D) {
if (!g_Instance->m_Texture2DShader.program) { if (!g_Instance->m_Texture2DShader.program) {
g_Instance->m_Texture2DShader = CreateProgram(k_VertexShader, k_FragmentShader2D); g_Instance->m_Texture2DShader = CreateProgram(k_VertexShader, k_FragmentShader2D);
} }
glUseProgram(g_Instance->m_Texture2DShader.program); glUseProgram(g_Instance->m_Texture2DShader.program);
glUniform2f(g_Instance->m_Texture2DShader.texcoord_scale_location, 1.0, 1.0); glUniform2f(g_Instance->m_Texture2DShader.texcoord_scale_location, 1.0, 1.0);
} }
else if (picture.texture_target == GL_TEXTURE_RECTANGLE_ARB) { else if (m_CurrentPicture.texture_target == GL_TEXTURE_RECTANGLE_ARB) {
if (!g_Instance->m_RectangleArbShader.program) { if (!g_Instance->m_RectangleArbShader.program) {
g_Instance->m_RectangleArbShader = CreateProgram(k_VertexShader, k_FragmentShaderRectangle); g_Instance->m_RectangleArbShader = CreateProgram(k_VertexShader, k_FragmentShaderRectangle);
} }
glUseProgram(g_Instance->m_RectangleArbShader.program); glUseProgram(g_Instance->m_RectangleArbShader.program);
glUniform2f(g_Instance->m_RectangleArbShader.texcoord_scale_location, glUniform2f(g_Instance->m_RectangleArbShader.texcoord_scale_location,
picture.texture_size.width, picture.texture_size.height); m_CurrentPicture.texture_size.width, m_CurrentPicture.texture_size.height);
} }
else if (picture.texture_target == GL_TEXTURE_EXTERNAL_OES) { else if (m_CurrentPicture.texture_target == GL_TEXTURE_EXTERNAL_OES) {
if (!g_Instance->m_ExternalOesShader.program) { if (!g_Instance->m_ExternalOesShader.program) {
g_Instance->m_ExternalOesShader = CreateProgram(k_VertexShader, k_FragmentShaderExternal); g_Instance->m_ExternalOesShader = CreateProgram(k_VertexShader, k_FragmentShaderExternal);
} }
@ -375,32 +350,31 @@ void MoonlightInstance::PaintPicture(void) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
s_LastTextureType = picture.texture_target; s_LastTextureType = m_CurrentPicture.texture_target;
} }
// Only rebind our texture if we've changed since last time // Only rebind our texture if we've changed since last time
if (picture.texture_id != s_LastTextureId || picture.texture_target != originalTextureTarget) { if (m_CurrentPicture.texture_id != s_LastTextureId || m_CurrentPicture.texture_target != originalTextureTarget) {
glBindTexture(picture.texture_target, picture.texture_id); glBindTexture(m_CurrentPicture.texture_target, m_CurrentPicture.texture_id);
s_LastTextureId = picture.texture_id; s_LastTextureId = m_CurrentPicture.texture_id;
} }
// Draw the image // Draw the image
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Swap buffers // Swap buffers
g_Instance->m_Graphics3D.SwapBuffers( m_Graphics3D.SwapBuffers(
g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::PaintFinished)); m_CallbackFactory.NewCallback(&MoonlightInstance::PaintFinished));
} }
void MoonlightInstance::PaintFinished(int32_t result) { void MoonlightInstance::PaintFinished(int32_t result) {
m_IsPainting = false; m_IsPainting = false;
// Recycle the picture now that it's been painted // Recycle the picture now that it's been painted
g_Instance->m_VideoDecoder->RecyclePicture(m_PendingPictureQueue.front()); m_VideoDecoder->RecyclePicture(m_CurrentPicture);
m_PendingPictureQueue.pop();
// Keep painting if we still have frames // Keep painting if we still have frames
if (!m_PendingPictureQueue.empty()) { if (m_HasNextPicture) {
PaintPicture(); PaintPicture();
} }
} }
@ -410,21 +384,21 @@ void MoonlightInstance::PictureReady(int32_t result, PP_VideoPicture picture) {
return; return;
} }
// Ensure we only push newer frames onto the display queue // Free a picture if there's one the renderer hasn't consumed yet
if (picture.decode_id > s_LastDisplayFrameNumber) { if (m_HasNextPicture) {
m_PendingPictureQueue.push(picture); m_VideoDecoder->RecyclePicture(m_NextPicture);
s_LastDisplayFrameNumber = picture.decode_id;
}
else {
// This picture is older than the last one we displayed. Discard
// it without displaying.
g_Instance->m_VideoDecoder->RecyclePicture(picture);
} }
// Put the latest picture in the slot for rendering next
m_NextPicture = picture;
m_HasNextPicture = true;
// Queue another call to get another picture
g_Instance->m_VideoDecoder->GetPicture( g_Instance->m_VideoDecoder->GetPicture(
g_Instance->m_CallbackFactory.NewCallbackWithOutput(&MoonlightInstance::PictureReady)); g_Instance->m_CallbackFactory.NewCallbackWithOutput(&MoonlightInstance::PictureReady));
if (!m_IsPainting && !m_PendingPictureQueue.empty()) { // Start painting if we aren't now
if (!m_IsPainting) {
PaintPicture(); PaintPicture();
} }
} }