diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index cd8a0d088..cf3141f5a 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -30,17 +30,24 @@ /* Sets an error message based on GetLastError() */ void -WIN_SetError(const char *prefix) +WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr) { TCHAR buffer[1024]; char *message; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, buffer, SDL_arraysize(buffer), NULL); message = WIN_StringToUTF8(buffer); SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message); SDL_free(message); } +/* Sets an error message based on GetLastError() */ +void +WIN_SetError(const char *prefix) +{ + WIN_SetErrorFromHRESULT(prefix, GetLastError()); +} + HRESULT WIN_CoInitialize(void) { diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index d4a7ecff9..3776b70eb 100644 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -46,6 +46,9 @@ #define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), SDL_strlen(S)+1) #endif +/* Sets an error message based on a given HRESULT */ +extern void WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr); + /* Sets an error message based on GetLastError() */ extern void WIN_SetError(const char *prefix); diff --git a/src/render/direct3d11/SDL_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp index 21f89fd01..6914f837b 100644 --- a/src/render/direct3d11/SDL_render_d3d11.cpp +++ b/src/render/direct3d11/SDL_render_d3d11.cpp @@ -62,7 +62,7 @@ static int D3D11_UpdateViewport(SDL_Renderer * renderer); // const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip); //static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, // Uint32 format, void * pixels, int pitch); -//static void D3D11_RenderPresent(SDL_Renderer * renderer); +static void D3D11_RenderPresent(SDL_Renderer * renderer); //static void D3D11_DestroyTexture(SDL_Renderer * renderer, // SDL_Texture * texture); //static void D3D11_DestroyRenderer(SDL_Renderer * renderer); @@ -135,7 +135,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) //renderer->RenderCopy = D3D11_RenderCopy; //renderer->RenderCopyEx = D3D11_RenderCopyEx; //renderer->RenderReadPixels = D3D11_RenderReadPixels; - //renderer->RenderPresent = D3D11_RenderPresent; + renderer->RenderPresent = D3D11_RenderPresent; //renderer->DestroyTexture = D3D11_DestroyTexture; //renderer->DestroyRenderer = D3D11_DestroyRenderer; renderer->info = D3D11_RenderDriver.info; @@ -286,6 +286,51 @@ D3D11_UpdateViewport(SDL_Renderer * renderer) return 0; } +static void +D3D11_RenderPresent(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // The first argument instructs DXGI to block until VSync, putting the application + // to sleep until the next VSync. This ensures we don't waste any cycles rendering + // frames that will never be displayed to the screen. + HRESULT hr = data->swapChain->Present(1, 0); +#else + // The application may optionally specify "dirty" or "scroll" + // rects to improve efficiency in certain scenarios. + // This option is not available on Windows Phone 8, to note. + DXGI_PRESENT_PARAMETERS parameters = {0}; + parameters.DirtyRectsCount = 0; + parameters.pDirtyRects = nullptr; + parameters.pScrollRect = nullptr; + parameters.pScrollOffset = nullptr; + + // The first argument instructs DXGI to block until VSync, putting the application + // to sleep until the next VSync. This ensures we don't waste any cycles rendering + // frames that will never be displayed to the screen. + HRESULT hr = data->swapChain->Present1(1, 0, ¶meters); +#endif + + // Discard the contents of the render target. + // This is a valid operation only when the existing contents will be entirely + // overwritten. If dirty or scroll rects are used, this call should be removed. + data->d3dContext->DiscardView(data->renderTargetView.Get()); + + // If the device was removed either by a disconnect or a driver upgrade, we + // must recreate all device resources. + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + extern void WINRT_HandleDeviceLost(); // TODO, WinRT: move lost-device handling into the Direct3D 11.1 renderer, as appropriate + WINRT_HandleDeviceLost(); + } + else + { + WIN_SetErrorFromHRESULT(__FUNCTION__, hr); + // TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvedge debug info from users' machines + } +} + #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/windowsrt/SDL_WinRTApp.cpp b/src/video/windowsrt/SDL_WinRTApp.cpp index 493d88195..aa204aa4d 100644 --- a/src/video/windowsrt/SDL_WinRTApp.cpp +++ b/src/video/windowsrt/SDL_WinRTApp.cpp @@ -33,6 +33,12 @@ static SDL_WinRT_MainFunction SDL_WinRT_main = nullptr; // SDL_CreateWindow(). SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr; +// HACK: provide a temporary means for the Direct3D 11.1 renderer to handle lost devices, while refactoring is underway +void WINRT_HandleDeviceLost() +{ + SDL_WinRTGlobalApp->m_renderer->HandleDeviceLost(); +} + using namespace Windows::ApplicationModel; using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Activation; diff --git a/src/video/windowsrt/SDL_winrtrenderer.cpp b/src/video/windowsrt/SDL_winrtrenderer.cpp index d8d960cb2..750473a04 100644 --- a/src/video/windowsrt/SDL_winrtrenderer.cpp +++ b/src/video/windowsrt/SDL_winrtrenderer.cpp @@ -12,6 +12,7 @@ SDL_winrtrenderer::SDL_winrtrenderer() : m_mainTextureHelperSurface(NULL), m_loadingComplete(false), m_vertexCount(0), + m_sdlRenderer(NULL), m_sdlRendererData(NULL) { } @@ -562,42 +563,7 @@ void SDL_winrtrenderer::Render(SDL_Surface * surface, SDL_Rect * rects, int numr // Method to deliver the final image to the display. void SDL_winrtrenderer::Present() { -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // The first argument instructs DXGI to block until VSync, putting the application - // to sleep until the next VSync. This ensures we don't waste any cycles rendering - // frames that will never be displayed to the screen. - HRESULT hr = m_sdlRendererData->swapChain->Present(1, 0); -#else - // The application may optionally specify "dirty" or "scroll" - // rects to improve efficiency in certain scenarios. - // This option is not available on Windows Phone 8, to note. - DXGI_PRESENT_PARAMETERS parameters = {0}; - parameters.DirtyRectsCount = 0; - parameters.pDirtyRects = nullptr; - parameters.pScrollRect = nullptr; - parameters.pScrollOffset = nullptr; - - // The first argument instructs DXGI to block until VSync, putting the application - // to sleep until the next VSync. This ensures we don't waste any cycles rendering - // frames that will never be displayed to the screen. - HRESULT hr = m_sdlRendererData->swapChain->Present1(1, 0, ¶meters); -#endif - - // Discard the contents of the render target. - // This is a valid operation only when the existing contents will be entirely - // overwritten. If dirty or scroll rects are used, this call should be removed. - m_sdlRendererData->d3dContext->DiscardView(m_sdlRendererData->renderTargetView.Get()); - - // If the device was removed either by a disconnect or a driver upgrade, we - // must recreate all device resources. - if (hr == DXGI_ERROR_DEVICE_REMOVED) - { - HandleDeviceLost(); - } - else - { - DX::ThrowIfFailed(hr); - } + SDL_RenderPresent(m_sdlRenderer); } // Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels. diff --git a/src/video/windowsrt/SDL_winrtrenderer.h b/src/video/windowsrt/SDL_winrtrenderer.h index 4f771947f..9d074245e 100644 --- a/src/video/windowsrt/SDL_winrtrenderer.h +++ b/src/video/windowsrt/SDL_winrtrenderer.h @@ -31,7 +31,8 @@ internal: void ResizeMainTexture(int w, int h); internal: - // Internal SDL rendeerer (likely a temporary addition, for refactoring purposes): + // Internal SDL renderer (likely a temporary addition, for refactoring purposes): + SDL_Renderer * m_sdlRenderer; D3D11_RenderData * m_sdlRendererData; protected private: diff --git a/src/video/windowsrt/SDL_winrtvideo.cpp b/src/video/windowsrt/SDL_winrtvideo.cpp index 6bd7640db..6c9098847 100644 --- a/src/video/windowsrt/SDL_winrtvideo.cpp +++ b/src/video/windowsrt/SDL_winrtvideo.cpp @@ -220,7 +220,10 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) // for refactoring purposes. Initialize the SDL_Renderer // first in order to give it the opportunity to create key // resources first. + // + // TODO, WinRT: either make WINRT_CreateWindow not call SDL_CreateRenderer, or have it do error checking if it does call it SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE); + SDL_WinRTGlobalApp->m_renderer->m_sdlRenderer = renderer; SDL_WinRTGlobalApp->m_renderer->m_sdlRendererData = (D3D11_RenderData *) renderer->driverdata; SDL_WinRTGlobalApp->m_renderer->Initialize(CoreWindow::GetForCurrentThread());