/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "StdAfx.h" #include "UnicodeFunctions.h" #include "DriverD3D.h" #include "WindowsUtils.h" #include "D3DGPUParticleEngine.h" #if defined(AZ_RESTRICTED_PLATFORM) #undef AZ_RESTRICTED_SECTION #define D3DSYSTEM_CPP_SECTION_1 1 #define D3DSYSTEM_CPP_SECTION_2 2 #define D3DSYSTEM_CPP_SECTION_3 3 #define D3DSYSTEM_CPP_SECTION_4 4 #define D3DSYSTEM_CPP_SECTION_5 5 #define D3DSYSTEM_CPP_SECTION_6 6 #define D3DSYSTEM_CPP_SECTION_7 7 #define D3DSYSTEM_CPP_SECTION_8 8 #define D3DSYSTEM_CPP_SECTION_9 9 #define D3DSYSTEM_CPP_SECTION_10 10 #define D3DSYSTEM_CPP_SECTION_11 11 #define D3DSYSTEM_CPP_SECTION_12 12 #define D3DSYSTEM_CPP_SECTION_13 13 #define D3DSYSTEM_CPP_SECTION_14 14 #define D3DSYSTEM_CPP_SECTION_15 15 #define D3DSYSTEM_CPP_SECTION_16 16 #define D3DSYSTEM_CPP_SECTION_17 17 #define D3DSYSTEM_CPP_SECTION_18 18 #define D3DSYSTEM_CPP_SECTION_19 19 #define D3DSYSTEM_CPP_SECTION_20 20 #define D3DSYSTEM_CPP_SECTION_21 21 #endif #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_1 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #include "D3DStereo.h" #include "D3DPostProcess.h" #include "D3DREBreakableGlassBuffer.h" #include "NullD3D11Device.h" #if defined(WIN32) // CryTek undefs some defines from WinBase.h...so let's redefine them here #ifdef UNICODE #define RegisterClass RegisterClassW #define LoadLibrary LoadLibraryW #else #define RegisterClass RegisterClassA #define LoadLibrary LoadLibraryA #endif // !UNICODE #include #pragma warning(push) #pragma warning(disable:4819) // Invalid character not in default code page #pragma warning(disable:4828) #include #pragma warning(pop) #endif // defined(WIN32) #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_2 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #include "../Common/RenderCapabilities.h" #ifdef WIN32 // Count monitors helper static BOOL CALLBACK CountConnectedMonitors(HMONITOR hMonitor, HDC hDC, LPRECT pRect, LPARAM opaque) { uint* count = reinterpret_cast(opaque); (*count)++; return TRUE; } #endif void CD3D9Renderer::DisplaySplash() { #ifdef WIN32 if (IsEditorMode()) { return; } HBITMAP hImage = (HBITMAP)LoadImage(GetModuleHandle(0), "splash.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); if (hImage != INVALID_HANDLE_VALUE) { RECT rect; HDC hDC = GetDC(m_hWnd); HDC hDCBitmap = CreateCompatibleDC(hDC); BITMAP bm; GetClientRect(m_hWnd, &rect); GetObjectA(hImage, sizeof(bm), &bm); SelectObject(hDCBitmap, hImage); DWORD x = rect.left + (((rect.right - rect.left) - bm.bmWidth) >> 1); DWORD y = rect.top + (((rect.bottom - rect.top) - bm.bmHeight) >> 1); // BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hDCBitmap, 0, 0, SRCCOPY); RECT Rect; GetWindowRect(m_hWnd, &Rect); StretchBlt(hDC, 0, 0, Rect.right - Rect.left, Rect.bottom - Rect.top, hDCBitmap, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); DeleteObject(hImage); DeleteDC(hDCBitmap); } #endif } //===================================================================================== bool CD3D9Renderer::SetCurrentContext(WIN_HWND hWnd) { uint32 i; for (i = 0; i < m_RContexts.Num(); i++) { if (m_RContexts[i]->m_hWnd == hWnd) { break; } } if (i == m_RContexts.Num()) { return false; } if (m_CurrContext == m_RContexts[i]) { return true; } m_CurrContext = m_RContexts[i]; CHWShader::s_pCurVS = NULL; CHWShader::s_pCurPS = NULL; return true; } bool CD3D9Renderer::CreateContext(WIN_HWND hWnd, bool bAllowMSAA, int SSX, int SSY) { LOADING_TIME_PROFILE_SECTION; uint32 i; for (i = 0; i < m_RContexts.Num(); i++) { if (m_RContexts[i]->m_hWnd == hWnd) { break; } } if (i != m_RContexts.Num()) { return true; } SD3DContext* pContext = new SD3DContext; pContext->m_hWnd = (HWND)hWnd; pContext->m_X = 0; pContext->m_Y = 0; pContext->m_Width = m_width; pContext->m_Height = m_height; pContext->m_pSwapChain = 0; pContext->m_pBackBuffer = 0; pContext->m_nViewportWidth = aznumeric_cast(aznumeric_cast(m_width) / (m_CurrContext ? m_CurrContext->m_fPixelScaleX : 1.0f)); pContext->m_nViewportHeight = aznumeric_cast(aznumeric_cast(m_height) / (m_CurrContext ? m_CurrContext->m_fPixelScaleY : 1.0f)); pContext->m_fPixelScaleX = aznumeric_cast(std::max(1, SSX)); pContext->m_fPixelScaleY = aznumeric_cast(std::max(1, SSY)); pContext->m_bMainViewport = !gEnv->IsEditor(); m_CurrContext = pContext; m_RContexts.AddElem(pContext); return true; } bool CD3D9Renderer::DeleteContext(WIN_HWND hWnd) { uint32 i, j; for (i = 0; i < m_RContexts.Num(); i++) { if (m_RContexts[i]->m_hWnd == hWnd) { break; } } if (i == m_RContexts.Num()) { return false; } if (m_CurrContext == m_RContexts[i]) { for (j = 0; j < m_RContexts.Num(); j++) { if (m_RContexts[j]->m_hWnd != hWnd) { m_CurrContext = m_RContexts[j]; break; } } if (j == m_RContexts.Num()) { m_CurrContext = NULL; } if (!m_CurrContext) { m_width = 0; m_height = 0; } else if (m_CurrContext->m_Width != m_width || m_CurrContext->m_Height != m_height) { m_width = m_CurrContext->m_Width; m_height = m_CurrContext->m_Height; } } for (unsigned int b = 0; b < m_RContexts[i]->m_pBackBuffers.size(); ++b) { SAFE_RELEASE(m_RContexts[i]->m_pBackBuffers[b]); } SAFE_RELEASE(m_RContexts[i]->m_pSwapChain); delete m_RContexts[i]; m_RContexts.Remove(i, 1); return true; } void CD3D9Renderer::MakeMainContextActive() { if (m_RContexts.empty() || m_CurrContext == m_RContexts[0]) { return; } m_CurrContext = m_RContexts[0]; CHWShader::s_pCurVS = NULL; CHWShader::s_pCurPS = NULL; } bool CD3D9Renderer::CreateMSAADepthBuffer() { HRESULT hr = S_OK; if (CV_r_msaa) { if (m_RP.m_MSAAData.Type != CV_r_msaa_samples || m_RP.m_MSAAData.Quality != CV_r_msaa_quality) { SAFE_RELEASE(m_RP.m_MSAAData.m_pZBuffer); SAFE_RELEASE(m_RP.m_MSAAData.m_pDepthTex); } m_RP.m_MSAAData.Type = CV_r_msaa_samples; m_RP.m_MSAAData.Quality = CV_r_msaa_quality; if (m_RP.m_MSAAData.Type > 1 && !m_RP.m_MSAAData.m_pZBuffer) { // Create depth stencil texture ID3D11Texture2D* pDepthStencil = NULL; D3D11_TEXTURE2D_DESC descDepth; ZeroStruct(descDepth); descDepth.Width = m_width; descDepth.Height = m_height; descDepth.MipLevels = 1; descDepth.ArraySize = 1; descDepth.Format = m_ZFormat; descDepth.SampleDesc.Count = m_RP.m_MSAAData.Type; descDepth.SampleDesc.Quality = m_RP.m_MSAAData.Quality; descDepth.Usage = D3D11_USAGE_DEFAULT; descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; // bind-able as shader resource view descDepth.CPUAccessFlags = 0; descDepth.MiscFlags = 0; const float clearDepth = CRenderer::CV_r_ReverseDepth ? 0.f : 1.f; const uint clearStencil = 1; const FLOAT clearValues[4] = { clearDepth, FLOAT(clearStencil) }; hr = m_DevMan.CreateD3D11Texture2D(&descDepth, clearValues, NULL, &m_RP.m_MSAAData.m_pDepthTex, "MSAADepthBuffer"); if (FAILED(hr)) { return false; } m_DepthBufferOrigMSAA.pTex = nullptr; m_DepthBufferOrigMSAA.pTarget = m_RP.m_MSAAData.m_pDepthTex; m_DepthBufferOrigMSAA.pSurf = m_RP.m_MSAAData.m_pZBuffer; // Create the depth stencil view D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; ZeroStruct(descDSV); descDSV.Format = CTexture::ConvertToDepthStencilFmt(descDepth.Format); descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; hr = GetDevice().CreateDepthStencilView(m_RP.m_MSAAData.m_pDepthTex, &descDSV, &m_RP.m_MSAAData.m_pZBuffer); if (FAILED(hr)) { return false; } m_DepthBufferOrigMSAA.pSurf = m_RP.m_MSAAData.m_pZBuffer; m_RP.m_MSAAData.m_pZBuffer->AddRef(); } } else { m_RP.m_MSAAData.Type = 0; m_RP.m_MSAAData.Quality = 0; SAFE_RELEASE(m_RP.m_MSAAData.m_pZBuffer); SAFE_RELEASE(m_RP.m_MSAAData.m_pDepthTex); SAFE_RELEASE(m_DepthBufferOrigMSAA.pSurf); m_DepthBufferOrigMSAA.pTex = nullptr; m_DepthBufferOrigMSAA.pSurf = m_pZBuffer; m_DepthBufferOrigMSAA.pTarget = m_pZTexture; m_pZBuffer->AddRef(); } return (hr == S_OK); } #if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES) static void UserOverrideDXGIOutputFS(DeviceInfo& devInfo, int outputIndex, int defaultX, int defaultY, int& outputX, int& outputY) { outputX = defaultX; outputY = defaultY; // This is not an ideal solution. Just for development or careful use. // The FS output override might be incompatible with output originally set up in device info. // As such selected resolutions might not be directly supported but currently won't fall back properly. # if (defined(WIN32) || defined(WIN64)) if (outputIndex > 0) { bool success = false; IDXGIOutput* pOutput = 0; if (SUCCEEDED(devInfo.Adapter()->EnumOutputs(outputIndex, &pOutput)) && pOutput) { DXGI_OUTPUT_DESC outputDesc; if (SUCCEEDED(pOutput->GetDesc(&outputDesc))) { MONITORINFO monitorInfo; monitorInfo.cbSize = sizeof(monitorInfo); if (GetMonitorInfo(outputDesc.Monitor, &monitorInfo)) { outputX = monitorInfo.rcMonitor.left; outputY = monitorInfo.rcMonitor.top; success = true; } } } SAFE_RELEASE(pOutput); if (!success) { CryLogAlways("Failed to resolve DXGI display for override index %d. Falling back to preferred or primary display.", outputIndex); } } # endif } #endif bool CD3D9Renderer::ChangeResolution(int nNewWidth, int nNewHeight, int nNewColDepth, int nNewRefreshHZ, bool bFullScreen, bool bForceReset) { if (m_bDeviceLost) { return true; } #if !defined(_RELEASE) && (defined(WIN32) || defined(WIN64) || defined(APPLE) || defined(LINUX)) if (m_pRT && !m_pRT->IsRenderThread()) { __debugbreak(); } #endif iLog->Log("Changing resolution..."); const int nPrevWidth = m_width; const int nPrevHeight = m_height; const int nPrevColorDepth = m_cbpp; const bool bPrevFullScreen = m_bFullScreen; if (nNewColDepth < 24) { nNewColDepth = 16; } else { nNewColDepth = 32; } bool bNeedReset = bForceReset || nNewColDepth != nPrevColorDepth || bFullScreen != bPrevFullScreen || nNewWidth != nPrevWidth || nNewHeight != nPrevHeight; #if !defined(SUPPORT_DEVICE_INFO) bNeedReset |= m_VSync != CV_r_vsync; #endif #if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES) bNeedReset |= m_overrideRefreshRate != CV_r_overrideRefreshRate || m_overrideScanlineOrder != CV_r_overrideScanlineOrder; #endif GetS3DRend().ReleaseBuffers(); DeleteContext(m_hWnd); // Save the new dimensions m_width = nNewWidth; m_height = nNewHeight; m_cbpp = nNewColDepth; m_bFullScreen = bFullScreen; #if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES) m_overrideRefreshRate = CV_r_overrideRefreshRate; m_overrideScanlineOrder = CV_r_overrideScanlineOrder; #endif if (!IsEditorMode()) { m_VSync = CV_r_vsync; } else { m_VSync = 0; } #if defined(SUPPORT_DEVICE_INFO) m_devInfo.SyncInterval() = m_VSync ? 1 : 0; #endif if (bFullScreen && nNewColDepth == 16) { m_zbpp = 16; m_sbpp = 0; } RestoreGamma(); bool bFullscreenWindow = false; #if defined(WIN32) || defined(WIN64) bFullscreenWindow = CV_r_FullscreenWindow && CV_r_FullscreenWindow->GetIVal() != 0; #endif if (IsEditorMode() && !bForceReset) { nNewWidth = m_deskwidth; nNewHeight = m_deskheight; } HRESULT hr = S_OK; if (bNeedReset) { #if defined(SUPPORT_DEVICE_INFO) #if defined(WIN32) // disable floating point exceptions due to driver bug when switching to fullscreen SCOPED_DISABLE_FLOAT_EXCEPTIONS; #endif m_devInfo.SwapChainDesc().Windowed = !bFullScreen; m_devInfo.SwapChainDesc().BufferDesc.Width = m_backbufferWidth; m_devInfo.SwapChainDesc().BufferDesc.Height = m_backbufferHeight; m_devInfo.SnapSettings(); int swapChainWidth = m_devInfo.SwapChainDesc().BufferDesc.Width; int swapChainHeight = m_devInfo.SwapChainDesc().BufferDesc.Height; if (m_backbufferWidth != swapChainWidth || m_backbufferHeight != swapChainHeight) { if (m_nativeWidth == m_backbufferWidth) { if (m_width == m_nativeWidth) { m_width = swapChainWidth; if (m_CVWidth) { m_CVWidth->Set(swapChainWidth); } } m_nativeWidth = swapChainWidth; } m_backbufferWidth = swapChainWidth; if (m_nativeHeight == m_backbufferHeight) { if (m_height == m_nativeHeight) { m_height = swapChainHeight; if (m_CVHeight) { m_CVHeight->Set(swapChainHeight); } } m_nativeHeight = swapChainHeight; } m_backbufferHeight = swapChainHeight; } ID3D11DepthStencilView* pDSV = 0; ID3D11RenderTargetView* pRTVs[8] = {0}; GetDeviceContext().OMSetRenderTargets(8, pRTVs, pDSV); m_DepthBufferOrig.Release(); m_DepthBufferOrigMSAA.Release(); m_DepthBufferNative.Release(); AdjustWindowForChange(); # if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES) UserOverrideDisplayProperties(m_devInfo.SwapChainDesc().BufferDesc); # endif m_pSwapChain->SetFullscreenState(bFullScreen, 0); m_pSwapChain->ResizeTarget(&m_devInfo.SwapChainDesc().BufferDesc); m_devInfo.ResizeDXGIBuffers(); OnD3D11PostCreateDevice(m_devInfo.Device()); #endif m_FullResRect.right = m_width; m_FullResRect.bottom = m_height; #if defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(APPLE) || defined(CREATE_DEVICE_ON_MAIN_THREAD) m_pRT->RC_SetViewport(0, 0, m_width, m_height); #else RT_SetViewport(0, 0, m_width, m_height); #endif #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_3 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif m_MainViewport.nX = 0; m_MainViewport.nY = 0; m_MainViewport.nWidth = m_width; m_MainViewport.nHeight = m_height; m_MainRTViewport.nX = 0; m_MainRTViewport.nY = 0; m_MainRTViewport.nWidth = m_width; m_MainRTViewport.nHeight = m_height; } AdjustWindowForChange(); GetS3DRend().OnResolutionChanged(); #ifdef WIN32 SetWindowText(m_hWnd, m_WinTitle); iLog->Log(" Window resolution: %dx%dx%d (%s)", m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, nNewColDepth, bFullScreen ? "Fullscreen" : "Windowed"); iLog->Log(" Render resolution: %dx%d)", m_width, m_height); #endif CreateMSAADepthBuffer(); CreateContext(m_hWnd, CV_r_msaa != 0); ICryFont* pCryFont = gEnv->pCryFont; if (pCryFont) { IFFont* pFont = pCryFont->GetFont("default"); } PostDeviceReset(); return true; } void CD3D9Renderer::PostDeviceReset() { m_bDeviceLost = 0; if (m_bFullScreen) { SetGamma(CV_r_gamma + m_fDeltaGamma, CV_r_brightness, CV_r_contrast, true); } FX_ResetPipe(); CHWShader::s_pCurVS = NULL; CHWShader::s_pCurPS = NULL; for (int i = 0; i < MAX_TMU; i++) { CTexture::s_TexStages[i].m_DevTexture = NULL; } m_nFrameReset++; } //----------------------------------------------------------------------------- // Name: CD3D9Renderer::AdjustWindowForChange() // Desc: Prepare the window for a possible change between windowed mode and // fullscreen mode. This function is virtual and thus can be overridden // to provide different behavior, such as switching to an entirely // different window for fullscreen mode (as in the MFC sample apps). //----------------------------------------------------------------------------- HRESULT CD3D9Renderer::AdjustWindowForChange() { #if defined(WIN32) if (IsEditorMode()) { return S_OK; } #if defined(OPENGL) const DXGI_SWAP_CHAIN_DESC& swapChainDesc(m_devInfo.SwapChainDesc()); DXGI_MODE_DESC modeDesc; modeDesc.Width = m_backbufferWidth; modeDesc.Height = m_backbufferHeight; modeDesc.RefreshRate = swapChainDesc.BufferDesc.RefreshRate; modeDesc.Format = swapChainDesc.BufferDesc.Format; modeDesc.ScanlineOrdering = swapChainDesc.BufferDesc.ScanlineOrdering; modeDesc.Scaling = swapChainDesc.BufferDesc.Scaling; HRESULT result = m_pSwapChain->ResizeTarget(&modeDesc); if (FAILED(result)) { return result; } #elif defined(WIN32) bool bFullscreenWindow = false; bFullscreenWindow = CV_r_FullscreenWindow && CV_r_FullscreenWindow->GetIVal() != 0; if (!m_bFullScreen && !bFullscreenWindow) { // Set windowed-mode style SetWindowLongW(m_hWnd, GWL_STYLE, m_dwWindowStyle); } else { // Set fullscreen-mode style SetWindowLongW(m_hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE); } if (m_bFullScreen) { int x = m_prefMonX; int y = m_prefMonY; #if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES) UserOverrideDXGIOutputFS(m_devInfo, CV_r_overrideDXGIOutputFS, m_prefMonX, m_prefMonY, x, y); #endif const int wdt = m_backbufferWidth; const int hgt = m_backbufferHeight; SetWindowPos(m_hWnd, HWND_TOPMOST, x, y, wdt, hgt, SWP_SHOWWINDOW); } else if (bFullscreenWindow) { const int x = m_prefMonX + (m_prefMonWidth - m_backbufferWidth) / 2; const int y = m_prefMonY + (m_prefMonHeight - m_backbufferHeight) / 2; const int wdt = m_backbufferWidth; const int hgt = m_backbufferHeight; SetWindowPos(m_hWnd, HWND_NOTOPMOST, x, y, wdt, hgt, SWP_SHOWWINDOW); } else { RECT wndrect; SetRect(&wndrect, 0, 0, m_backbufferWidth, m_backbufferHeight); AdjustWindowRectEx(&wndrect, m_dwWindowStyle, FALSE, WS_EX_APPWINDOW); const int wdt = wndrect.right - wndrect.left; const int hgt = wndrect.bottom - wndrect.top; const int x = m_prefMonX + (m_prefMonWidth - wdt) / 2; const int y = m_prefMonY + (m_prefMonHeight - hgt) / 2; SetWindowPos(m_hWnd, HWND_NOTOPMOST, x, y, wdt, hgt, SWP_SHOWWINDOW); } #endif //set viewport to ensure we have a valid one, even when doing chainloading // and playing a video before going ingame m_MainViewport.nX = 0; m_MainViewport.nY = 0; m_MainViewport.nWidth = m_width; m_MainViewport.nHeight = m_height; m_MainRTViewport.nX = 0; m_MainRTViewport.nY = 0; m_MainRTViewport.nWidth = m_width; m_MainRTViewport.nHeight = m_height; m_FullResRect.right = m_width; m_FullResRect.bottom = m_height; m_pRT->RC_SetViewport(0, 0, m_width, m_height); #endif return S_OK; } #if defined(SUPPORT_DEVICE_INFO) bool compareDXGIMODEDESC(const DXGI_MODE_DESC& lhs, const DXGI_MODE_DESC& rhs) { if (lhs.Width != rhs.Width) { return lhs.Width < rhs.Width; } return lhs.Height < rhs.Height; } #endif int CD3D9Renderer::EnumDisplayFormats(SDispFormat* formats) { #if defined(WIN32) || defined(WIN64) || defined(OPENGL) #if defined(SUPPORT_DEVICE_INFO) unsigned int numModes = 0; if (m_devInfo.Output()) { if (SUCCEEDED(m_devInfo.Output()->GetDisplayModeList(m_devInfo.SwapChainDesc().BufferDesc.Format, 0, &numModes, 0)) && numModes) { std::vector dispModes(numModes); if (SUCCEEDED(m_devInfo.Output()->GetDisplayModeList(m_devInfo.SwapChainDesc().BufferDesc.Format, 0, &numModes, &dispModes[0])) && numModes) { std::sort(dispModes.begin(), dispModes.end(), compareDXGIMODEDESC); unsigned int numUniqueModes = 0; unsigned int prevWidth = 0; unsigned int prevHeight = 0; for (unsigned int i = 0; i < numModes; ++i) { if (prevWidth != dispModes[i].Width || prevHeight != dispModes[i].Height) { if (formats) { formats[numUniqueModes].m_Width = dispModes[i].Width; formats[numUniqueModes].m_Height = dispModes[i].Height; formats[numUniqueModes].m_BPP = CTexture::BytesPerBlock(CTexture::TexFormatFromDeviceFormat(dispModes[i].Format)) * 8; } prevWidth = dispModes[i].Width; prevHeight = dispModes[i].Height; ++numUniqueModes; } } numModes = numUniqueModes; } } } return numModes; #endif #else return 0; #endif } bool CD3D9Renderer::ChangeDisplay(unsigned int width, unsigned int height, unsigned int cbpp) { return false; } void CD3D9Renderer::UnSetRes() { m_Features |= RFT_SUPPORTZBIAS; #if defined(SUPPORT_D3D_DEBUG_RUNTIME) m_d3dDebug.Release(); #endif } void CD3D9Renderer::DestroyWindow(void) { #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_4 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(OPENGL) // Scrubber safe exclusion #else SAFE_RELEASE(m_DeviceContext); #endif SAFE_RELEASE(m_Device); #if defined(CRY_USE_METAL) DXGLDestroyMetalWindow(m_hWnd); #elif defined(WIN32) if (gEnv && gEnv->pSystem) { if (m_registeredWindoWHandler) { gEnv->pSystem->UnregisterWindowMessageHandler(this); } m_registeredWindoWHandler = false; } if (m_hWnd) { ::DestroyWindow(m_hWnd); m_hWnd = NULL; } if (m_hWnd2) { ::DestroyWindow(m_hWnd2); m_hWnd2 = NULL; } if (m_hIconBig) { ::DestroyIcon(m_hIconBig); m_hIconBig = NULL; } if (m_hIconSmall) { ::DestroyIcon(m_hIconSmall); m_hIconSmall = NULL; } #elif defined(OPENGL) DXGLDestroyWindow(m_hWnd); #endif } struct CD3D9Renderer::gammaramp_t { uint16 red[256]; uint16 green[256]; uint16 blue[256]; }; static CD3D9Renderer::gammaramp_t orgGamma; static BOOL g_doGamma = false; void CD3D9Renderer::RestoreGamma(void) { if (!(GetFeatures() & RFT_HWGAMMA)) { return; } if (CV_r_nohwgamma && m_nLastNoHWGamma) { return; } m_nLastNoHWGamma = CV_r_nohwgamma; m_fLastGamma = 1.0f; m_fLastBrightness = 0.5f; m_fLastContrast = 0.5f; //iLog->Log("...RestoreGamma"); #if defined(WIN32) if (!g_doGamma) { return; } g_doGamma = false; m_hWndDesktop = GetDesktopWindow(); if (HDC dc = GetDC(m_hWndDesktop)) { SetDeviceGammaRamp(dc, &orgGamma); ReleaseDC(m_hWndDesktop, dc); } #endif } void CD3D9Renderer::GetDeviceGamma() { #if defined(WIN32) if (g_doGamma) { return; } m_hWndDesktop = GetDesktopWindow(); if (HDC dc = GetDC(m_hWndDesktop)) { g_doGamma = true; if (!GetDeviceGammaRamp(dc, &orgGamma)) { for (uint16 i = 0; i < 256; i++) { orgGamma.red [i] = i * 0x101; orgGamma.green[i] = i * 0x101; orgGamma.blue [i] = i * 0x101; } } ReleaseDC(m_hWndDesktop, dc); } #endif } void CD3D9Renderer::SetDeviceGamma(gammaramp_t* gamma) { if (!(GetFeatures() & RFT_HWGAMMA)) { return; } if (CV_r_nohwgamma) { return; } #if defined(WIN32) if (!g_doGamma) { return; } m_hWndDesktop = GetDesktopWindow(); // TODO: DesktopWindow - does not represent actual output window thus gamma affects all desktop monitors !!! if (HDC dc = GetDC(m_hWndDesktop)) { g_doGamma = true; // INFO!!! - very strange: in the same time // GetDeviceGammaRamp -> TRUE // SetDeviceGammaRamp -> FALSE but WORKS!!! // at least for desktop window DC... be careful SetDeviceGammaRamp(dc, gamma); ReleaseDC(m_hWndDesktop, dc); } #endif } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// void CD3D9Renderer::SetGamma(float fGamma, float fBrightness, float fContrast, bool bForce) { // Early out if HW gamma is disabled (same early out as SetDeviceGamma) if (CV_r_nohwgamma) { // Restore default if HW gamma was previously enabled if (m_nLastNoHWGamma == 0) { RestoreGamma(); } return; } if (m_pStereoRenderer) // Function can be called on shutdown { fGamma += GetS3DRend().GetGammaAdjustment(); } fGamma = CLAMP(fGamma, 0.4f, 1.6f); if (!bForce && m_fLastGamma == fGamma && m_fLastBrightness == fBrightness && m_fLastContrast == fContrast && m_nLastNoHWGamma == CV_r_nohwgamma) { return; } GetDeviceGamma(); gammaramp_t gamma; float fInvGamma = 1.f / fGamma; float fAdd = (fBrightness - 0.5f) * 0.5f - fContrast * 0.5f + 0.25f; float fMul = fContrast + 0.5f; for (int i = 0; i < 256; i++) { float pfInput[3]; pfInput[0] = (float)(orgGamma.red [i] >> 8) / 255.f; pfInput[1] = (float)(orgGamma.green[i] >> 8) / 255.f; pfInput[2] = (float)(orgGamma.blue [i] >> 8) / 255.f; pfInput[0] = pow_tpl(pfInput[0], fInvGamma) * fMul + fAdd; pfInput[1] = pow_tpl(pfInput[1], fInvGamma) * fMul + fAdd; pfInput[2] = pow_tpl(pfInput[2], fInvGamma) * fMul + fAdd; gamma.red [i] = CLAMP(int_round(pfInput[0] * 65535.f), 0, 65535); gamma.green[i] = CLAMP(int_round(pfInput[1] * 65535.f), 0, 65535); gamma.blue [i] = CLAMP(int_round(pfInput[2] * 65535.f), 0, 65535); } SetDeviceGamma(&gamma); m_nLastNoHWGamma = CV_r_nohwgamma; m_fLastGamma = fGamma; m_fLastBrightness = fBrightness; m_fLastContrast = fContrast; } bool CD3D9Renderer::SetGammaDelta(const float fGamma) { m_fDeltaGamma = fGamma; SetGamma(CV_r_gamma + fGamma, CV_r_brightness, CV_r_contrast, false); return true; } SDepthTexture::~SDepthTexture() { } void SDepthTexture::Release(bool bReleaseTex) { SAFE_RELEASE(pSurf); if (bReleaseTex && pTarget) { gcpRendD3D->m_DevMan.ReleaseD3D11Texture2D(static_cast(pTarget)); pTex = nullptr; } } void CD3D9Renderer::ShutDownFast() { // Flush RT command buffer ForceFlushRTCommands(); CHWShader::mfFlushPendedShadersWait(-1); FX_PipelineShutdown(true); //CBaseResource::ShutDown(); memset(&CTexture::s_TexStages[0], 0, sizeof(CTexture::s_TexStages)); for (uint32 i = 0; i < CTexture::s_TexStates.size(); i++) { memset(&CTexture::s_TexStates[i], 0, sizeof(STexState)); } SAFE_DELETE(m_pRT); #if defined(OPENGL) #if !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL) if (CV_r_multithreaded) { DXGLReleaseContext(m_devInfo.Device()); } #endif //!DXGL_FULL_EMULATION m_devInfo.Release(); #endif //defined(OPENGL) } void CD3D9Renderer::RT_ShutDown(uint32 nFlags) { m_volumetricFog.DestroyResources(true); #if ENABLE_CRY_PHYSICS CREBreakableGlassBuffer::RT_ReleaseInstance(); #endif SAFE_DELETE(m_pColorGradingControllerD3D); SAFE_DELETE(m_pPostProcessMgr); SAFE_DELETE(m_pWaterSimMgr); SAFE_DELETE(m_pStereoRenderer); SAFE_DELETE(m_pPipelineProfiler); m_PerInstanceConstantBufferPool.Shutdown(); for (size_t bt = 0; bt < eBoneType_Count; ++bt) { for (size_t i = 0; i < 3; ++i) { while (m_CharCBActiveList[bt][i].next != &m_CharCBActiveList[bt][i]) { delete m_CharCBActiveList[bt][i].next->item<&SCharInstCB::list>(); } } while (m_CharCBFreeList[bt].next != &m_CharCBFreeList[bt]) { delete m_CharCBFreeList[bt].next->item<&SCharInstCB::list>(); } } CHWShader::mfFlushPendedShadersWait(-1); if (nFlags == FRR_ALL) { memset(&CTexture::s_TexStages[0], 0, sizeof(CTexture::s_TexStages)); CTexture::s_TexStates.clear(); FreeResources(FRR_ALL); } FX_PipelineShutdown(); #if defined(SUPPORT_DEVICE_INFO) //m_devInfo.Release(); # if defined(OPENGL) && !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL) m_pRT->m_kDXGLDeviceContextHandle.Set(NULL, !CV_r_multithreaded); m_pRT->m_kDXGLContextHandle.Set(NULL); # endif //if defined(OPENGL) && !DXGL_FULL_EMULATION #endif SAFE_RELEASE(m_pZBufferReadOnlyDSV); SAFE_RELEASE(m_pZBufferDepthReadOnlySRV); SAFE_RELEASE(m_pZBufferStencilReadOnlySRV); SAFE_DELETE(m_GraphicsPipeline); #if defined(ENABLE_RENDER_AUX_GEOM) SAFE_DELETE(m_pRenderAuxGeomD3D); #endif m_DepthBufferOrig.pSurf = NULL; m_DepthBufferOrig.pTex = NULL; m_DepthBufferOrigMSAA.pSurf = NULL; m_DepthBufferOrigMSAA.pTex = NULL; m_DepthBufferNative.pSurf = NULL; m_DepthBufferNative.pTex = NULL; } void CD3D9Renderer::ShutDown(bool bReInit) { m_bInShutdown = true; // Force Flush RT command buffer ForceFlushRTCommands(); PreShutDown(); CWaterRipples::ReleasePhysCallbacks(); if (m_pRT) { m_pRT->RC_ShutDown(bReInit ? (FRR_SHADERS | FRR_TEXTURES | FRR_REINITHW) : FRR_ALL); } //CBaseResource::ShutDown(); ForceFlushRTCommands(); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_5 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif ////////////////////////////////////////////////////////////////////////// // Clear globals. ////////////////////////////////////////////////////////////////////////// STLALLOCATOR_CLEANUP SAFE_DELETE(m_pRT); #if defined(OPENGL) #if !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL) if (CV_r_multithreaded) { DXGLReleaseContext(&GetDevice()); } #endif //!DXGL_FULL_EMULATION m_devInfo.Release(); #endif //defined(OPENGL) if (!bReInit) { iLog = NULL; //iConsole = NULL; iTimer = NULL; iSystem = NULL; } EnableGPUTimers2(false); AllowGPUTimers2(false); #if defined(OPENGL) && !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL) DXGLFinalize(); #endif //defined(OPENGL) && !DXGL_FULL_EMULATION PostShutDown(); } #ifdef WIN32 LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LPARAM lParam) { KBDLLHOOKSTRUCT* pkbhs = (KBDLLHOOKSTRUCT*) lParam; BOOL bControlKeyDown = 0; switch (nCode) { case HC_ACTION: { if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN) { return 1; // Disable ALT+ESC } } default: break; } return CallNextHookEx (0, nCode, wParam, lParam); } #endif #if defined(SUPPORT_DEVICE_INFO) HWND CD3D9Renderer::CreateWindowCallback() { gcpRendD3D->SetWindow(gcpRendD3D->GetBackbufferWidth(), gcpRendD3D->GetBackbufferHeight(), gcpRendD3D->m_bFullScreen, gcpRendD3D->m_hWnd); return gcpRendD3D->m_hWnd; } #endif bool CD3D9Renderer::SetWindow(int width, int height, bool fullscreen, WIN_HWND hWnd) { LOADING_TIME_PROFILE_SECTION; #if D3DSYSTEM_CPP_TRAIT_SETWINDOW_REGISTERWINDOWMESSAGEHANDLER iSystem->RegisterWindowMessageHandler(this); m_registeredWindoWHandler = true; #endif #if defined(CRY_USE_METAL) if (gcpRendD3D->m_hWnd == 0) { DXGLCreateMetalWindow(m_WinTitle, width, height, fullscreen, &m_hWnd); } #elif defined(WIN32) DWORD style, exstyle; int x, y, wdt, hgt; if (width < 640) { width = 640; } if (height < 480) { height = 480; } m_dwWindowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE; // Do not allow the user to resize the window m_dwWindowStyle &= ~WS_MAXIMIZEBOX; m_dwWindowStyle &= ~WS_THICKFRAME; bool bFullscreenWindow = false; #if defined(WIN32) || defined(WIN64) bFullscreenWindow = CV_r_FullscreenWindow && CV_r_FullscreenWindow->GetIVal() != 0; #endif if (fullscreen || bFullscreenWindow) { exstyle = bFullscreenWindow ? WS_EX_APPWINDOW : WS_EX_TOPMOST; style = WS_POPUP | WS_VISIBLE; x = m_prefMonX + (m_prefMonWidth - width) / 2; y = m_prefMonY + (m_prefMonHeight - height) / 2; wdt = width; hgt = height; } else { exstyle = WS_EX_APPWINDOW; style = m_dwWindowStyle; RECT wndrect; SetRect(&wndrect, 0, 0, width, height); AdjustWindowRectEx(&wndrect, style, FALSE, exstyle); wdt = wndrect.right - wndrect.left; hgt = wndrect.bottom - wndrect.top; x = m_prefMonX + (m_prefMonWidth - wdt) / 2; y = m_prefMonY + (m_prefMonHeight - hgt) / 2; } if (IsEditorMode()) { #if defined(UNICODE) || defined(_UNICODE) #error Review this, probably should be wide if Editor also has UNICODE support (or maybe moved into Editor) #endif m_dwWindowStyle = WS_OVERLAPPED; style = m_dwWindowStyle; exstyle = 0; x = y = 0; wdt = 100; hgt = 100; WNDCLASSA wc; memset(&wc, 0, sizeof(WNDCLASSA)); wc.style = CS_OWNDC; wc.lpfnWndProc = DefWindowProcA; wc.hInstance = m_hInst; wc.lpszClassName = "D3DDeviceWindowClassForSandbox"; if (!RegisterClassA(&wc)) { CryFatalError("Cannot Register Window Class %s", wc.lpszClassName); return false; } m_hWnd = CreateWindowExA(exstyle, wc.lpszClassName, m_WinTitle, style, x, y, wdt, hgt, NULL, NULL, m_hInst, NULL); ShowWindow(m_hWnd, SW_HIDE); } else { if (!hWnd) { LPCWSTR pClassName = L"CryENGINE"; // Load default icon if we have nothing yet if (m_hIconBig == NULL) { SetWindowIcon("textures/default_icon.dds"); } // Moved from Game DLL WNDCLASSEXW wc; memset(&wc, 0, sizeof(WNDCLASSEXW)); wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wc.lpfnWndProc = (WNDPROC)GetISystem()->GetRootWindowMessageHandler(); wc.hInstance = m_hInst; wc.hIcon = m_hIconBig; wc.hIconSm = m_hIconSmall; wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszClassName = pClassName; if (!RegisterClassExW(&wc)) { CryFatalError("Cannot Register Launcher Window Class"); return false; } wstring wideTitle = Unicode::Convert(m_WinTitle); m_hWnd = CreateWindowExW(exstyle, pClassName, wideTitle.c_str(), style, x, y, wdt, hgt, NULL, NULL, m_hInst, NULL); if (m_hWnd && !IsWindowUnicode(m_hWnd)) { CryFatalError("Expected an UNICODE window for launcher"); return false; } // Create second window for stereo (multi-head device) if (GetS3DRend().GetStereoDevice() == STEREO_DEVICE_DUALHEAD && fullscreen) { m_hWnd2 = CreateWindowExW(exstyle, pClassName, wideTitle.c_str(), style, x, y, wdt, hgt, m_hWnd, NULL, m_hInst, NULL); } else { m_hWnd2 = 0; } EnableCloseButton(m_hWnd, false); if (fullscreen && (!gEnv->pSystem->IsDevMode() && CV_r_enableAltTab == 0)) { SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, 0); } } else { m_hWnd = (HWND)hWnd; } ShowWindow(m_hWnd, SW_SHOWNORMAL); SetFocus(m_hWnd); SetForegroundWindow(m_hWnd); } if (!m_hWnd) { iConsole->Exit("Couldn't create window\n"); } #elif defined(OPENGL) return DXGLCreateWindow(m_WinTitle, width, height, fullscreen, &m_hWnd); #else return false; #endif //WIN32 return true; } bool CD3D9Renderer::SetWindowIcon(const char* path) { #ifdef WIN32 if (IsEditorMode()) { return false; } if (azstricmp(path, m_iconPath.c_str()) == 0) { return true; } HICON hIconBig = CreateResourceFromTexture(this, path, eResourceType_IconBig); if (hIconBig) { if (m_hWnd) { SendMessage(m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIconBig); } if (m_hWnd2) { SendMessage(m_hWnd2, WM_SETICON, ICON_BIG, (LPARAM)hIconBig); } if (m_hIconBig) { ::DestroyIcon(m_hIconBig); } m_hIconBig = hIconBig; m_iconPath = path; } // Note: Also set the small icon manually. // Even though the big icon will also affect the small icon, the re-scaling done by GDI has aliasing problems. // Just grabbing a smaller MIP from the texture (if possible) will solve this. HICON hIconSmall = CreateResourceFromTexture(this, path, eResourceType_IconSmall); if (hIconSmall) { if (m_hWnd) { SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall); } if (m_hWnd) { SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall); } if (m_hIconSmall) { ::DestroyIcon(m_hIconSmall); } m_hIconSmall = hIconSmall; } return hIconBig != NULL; #else return false; #endif } #define QUALITY_VAR(name) \ static void OnQShaderChange_Shader##name(ICVar * pVar) \ { \ int iQuality = eSQ_Low; \ if (gRenDev->GetFeatures() & (RFT_HW_SM2X | RFT_HW_SM30)) { \ iQuality = CLAMP(pVar->GetIVal(), 0, eSQ_Max); } \ gRenDev->EF_SetShaderQuality(eST_##name, (EShaderQuality)iQuality); \ } QUALITY_VAR(General) QUALITY_VAR(Metal) QUALITY_VAR(Glass) QUALITY_VAR(Vegetation) QUALITY_VAR(Ice) QUALITY_VAR(Terrain) QUALITY_VAR(Shadow) QUALITY_VAR(Water) QUALITY_VAR(FX) QUALITY_VAR(PostProcess) QUALITY_VAR(HDR) QUALITY_VAR(Sky) #undef QUALITY_VAR static void OnQShaderChange_Renderer(ICVar* pVar) { int iQuality = eRQ_Low; if (gRenDev->GetFeatures() & (RFT_HW_SM2X | RFT_HW_SM30)) { iQuality = CLAMP(pVar->GetIVal(), 0, eSQ_Max); } else { pVar->ForceSet("0"); } gRenDev->m_RP.m_eQuality = (ERenderQuality)iQuality; } static void Command_Quality(IConsoleCmdArgs* Cmd) { bool bLog = false; bool bSet = false; int iQuality = -1; if (Cmd->GetArgCount() == 2) { iQuality = CLAMP(atoi(Cmd->GetArg(1)), eSQ_Low, eSQ_VeryHigh); bSet = true; } else { bLog = true; } if (bLog) { iLog->LogWithType(IMiniLog::eInputResponse, " "); } if (bLog) { iLog->LogWithType(IMiniLog::eInputResponse, "Current quality settings (0=low/1=med/2=high/3=very high):"); } #define QUALITY_VAR(name) if (bLog) {iLog->LogWithType(IMiniLog::eInputResponse, " $3q_"#name " = $6%d", gEnv->pConsole->GetCVar("q_"#name)->GetIVal()); } \ if (bSet) { gEnv->pConsole->GetCVar("q_"#name)->Set(iQuality); } QUALITY_VAR(ShaderGeneral) QUALITY_VAR(ShaderMetal) QUALITY_VAR(ShaderGlass) QUALITY_VAR(ShaderVegetation) QUALITY_VAR(ShaderIce) QUALITY_VAR(ShaderTerrain) QUALITY_VAR(ShaderShadow) QUALITY_VAR(ShaderWater) QUALITY_VAR(ShaderFX) QUALITY_VAR(ShaderPostProcess) QUALITY_VAR(ShaderHDR) QUALITY_VAR(ShaderSky) QUALITY_VAR(Renderer) #undef QUALITY_VAR if (bSet) { iLog->LogWithType(IMiniLog::eInputResponse, "Set quality to %d", iQuality); } } const char* sGetSQuality(const char* szName) { ICVar* pVar = iConsole->GetCVar(szName); assert(pVar); if (!pVar) { return "Unknown"; } int iQ = pVar->GetIVal(); switch (iQ) { case eSQ_Low: return "Low"; case eSQ_Medium: return "Medium"; case eSQ_High: return "High"; case eSQ_VeryHigh: return "VeryHigh"; default: return "Unknown"; } } static void Command_ColorGradingChartImage(IConsoleCmdArgs* pCmd) { CColorGradingControllerD3D* pCtrl = gcpRendD3D->m_pColorGradingControllerD3D; if (pCmd && pCtrl) { const int numArgs = pCmd->GetArgCount(); if (numArgs == 1) { const CTexture* pChart = pCtrl->GetStaticColorChart(); if (pChart) { iLog->Log("current static chart is \"%s\"", pChart->GetName()); } else { iLog->Log("no static chart loaded"); } } else if (numArgs == 2) { const char* pArg = pCmd->GetArg(1); if (pArg && pArg[0]) { if (pArg[0] == '0' && !pArg[1]) { pCtrl->LoadStaticColorChart(0); iLog->Log("static chart reset"); } else { if (pCtrl->LoadStaticColorChart(pArg)) { iLog->Log("\"%s\" loaded successfully", pArg); } else { iLog->Log("failed to load \"%s\"", pArg); } } } } } } WIN_HWND CD3D9Renderer::Init(int x, int y, int width, int height, unsigned int cbpp, int zbpp, int sbits, bool fullscreen, bool isEditor, WIN_HINSTANCE hinst, WIN_HWND Glhwnd, bool bReInit, const SCustomRenderInitArgs* pCustomArgs, bool bShaderCacheGen) { LOADING_TIME_PROFILE_SECTION; if (!iSystem || !iLog) { AZ_Error("CD3D9Renderer::Init", iSystem, "Renderer initialization failed because iSystem was null."); AZ_Error("CD3D9Renderer::Init", iLog, "Renderer initialization failed because iLog was null."); return 0; } iLog->Log("Initializing Direct3D and creating game window:"); INDENT_LOG_DURING_SCOPE(); m_CVWidth = iConsole->GetCVar("r_Width"); m_CVHeight = iConsole->GetCVar("r_Height"); m_CVFullScreen = iConsole->GetCVar("r_Fullscreen"); m_CVDisplayInfo = iConsole->GetCVar("r_DisplayInfo"); m_CVColorBits = iConsole->GetCVar("r_ColorBits"); bool bNativeResolution; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_6 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(IOS) bNativeResolution = true; #elif defined(APPLETV) bNativeResolution = true; #elif defined(ANDROID) bNativeResolution = true; #elif defined(WIN32) || defined(WIN64) CV_r_FullscreenWindow = iConsole->GetCVar("r_FullscreenWindow"); m_fullscreenWindow = CV_r_FullscreenWindow && CV_r_FullscreenWindow->GetIVal(); CV_r_FullscreenNativeRes = iConsole->GetCVar("r_FullscreenNativeRes"); bNativeResolution = CV_r_FullscreenNativeRes && CV_r_FullscreenNativeRes->GetIVal() != 0 && (fullscreen || m_fullscreenWindow); { RECT rcDesk; GetWindowRect(GetDesktopWindow(), &rcDesk); m_prefMonX = rcDesk.left; m_prefMonY = rcDesk.top; m_prefMonWidth = rcDesk.right - rcDesk.left; m_prefMonHeight = rcDesk.bottom - rcDesk.top; } { RECT rc; HDC hdc = GetDC(NULL); GetClipBox(hdc, &rc); ReleaseDC(NULL, hdc); m_deskwidth = rc.right - rc.left; m_deskheight = rc.bottom - rc.top; } #else bNativeResolution = false; #endif #if defined(OPENGL) && !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL) DXGLInitialize(CV_r_multithreaded ? 4 : 0); #endif //defined(OPENGL) && !DXGL_FULL_EMULATION #ifdef D3DX_SDK_VERSION iLog->Log("D3DX_SDK_VERSION = %d", D3DX_SDK_VERSION); #else iLog->Log("D3DX_SDK_VERSION = "); #endif iLog->Log ("Direct3D driver is creating..."); iLog->Log ("Crytek Direct3D driver version %4.2f (%s <%s>)", VERSION_D3D, __DATE__, __TIME__); const char* sGameName = iConsole->GetCVar("sys_game_name")->GetString(); cry_strcpy(m_WinTitle, sGameName); iLog->Log ("Creating window called '%s' (%dx%d)", m_WinTitle, width, height); m_hInst = (HINSTANCE)(TRUNCATE_PTR)hinst; m_bEditor = isEditor; if (isEditor) { fullscreen = false; } m_bShaderCacheGen = bShaderCacheGen; m_cbpp = cbpp; m_zbpp = zbpp; m_sbpp = sbits; m_bFullScreen = fullscreen; CalculateResolutions(width, height, bNativeResolution, &m_width, &m_height, &m_nativeWidth, &m_nativeHeight, &m_backbufferWidth, &m_backbufferHeight); // only create device if we are not in shader cache generation mode if (!m_bShaderCacheGen) { // call init stereo before device is created! m_pStereoRenderer->InitDeviceBeforeD3D(); while (true) { m_hWnd = (HWND)Glhwnd; // Creates Device here. bool bRes = m_pRT->RC_CreateDevice(); if (!bRes) { ShutDown(true); return 0; } break; } # if defined(SUPPORT_DEVICE_INFO) iLog->Log(" ****** D3D11 CryRender Stats ******"); iLog->Log(" Driver description: %S", m_devInfo.AdapterDesc().Description); switch (m_devInfo.FeatureLevel()) { case D3D_FEATURE_LEVEL_9_1: iLog->Log(" Feature level: DirectX 9.1"); break; case D3D_FEATURE_LEVEL_9_2: iLog->Log(" Feature level: DirectX 9.2"); break; case D3D_FEATURE_LEVEL_9_3: iLog->Log(" Feature level: DirectX 9.3"); break; case D3D_FEATURE_LEVEL_10_0: iLog->Log(" Feature level: DirectX 10.0"); break; case D3D_FEATURE_LEVEL_10_1: iLog->Log(" Feature level: DirectX 10.1"); break; case D3D_FEATURE_LEVEL_11_0: iLog->Log(" Feature level: DirectX 11.0"); break; } if (m_devInfo.DriverType() == D3D_DRIVER_TYPE_HARDWARE) { iLog->Log(" Rasterizer: Hardware"); } else if (m_devInfo.DriverType() == D3D_DRIVER_TYPE_REFERENCE) { iLog->Log(" Rasterizer: Reference"); } else if (m_devInfo.DriverType() == D3D_DRIVER_TYPE_SOFTWARE) { iLog->Log(" Rasterizer: Software"); } # endif iLog->Log(" Current Resolution: %dx%dx%d %s", CRenderer::m_width, CRenderer::m_height, CRenderer::m_cbpp, m_bFullScreen ? "Full Screen" : "Windowed"); iLog->Log(" HDR Rendering: %s", m_nHDRType == 1 ? "FP16" : m_nHDRType == 2 ? "MRT" : "Disabled"); iLog->Log(" MRT HDR Rendering: %s", (m_bDeviceSupportsFP16Separate) ? "Enabled" : "Disabled"); iLog->Log(" Occlusion queries: %s", (m_Features & RFT_OCCLUSIONTEST) ? "Supported" : "Not supported"); iLog->Log(" Geometry instancing: %s", (m_bDeviceSupportsInstancing) ? "Supported" : "Not supported"); iLog->Log(" Vertex textures: %s", (m_bDeviceSupportsVertexTexture) ? "Supported" : "Not supported"); iLog->Log(" R32F rendertarget: %s", (m_bDeviceSupportsR32FRendertarget) ? "Supported" : "Not supported"); iLog->Log(" NormalMaps compression : %s", m_hwTexFormatSupport.m_FormatBC5U.IsValid() ? "Supported" : "Not supported"); iLog->Log(" Gamma control: %s", (m_Features & RFT_HWGAMMA) ? "Hardware" : "Software"); iLog->Log(" Vertex Shaders version %d.%d", 4, 0); iLog->Log(" Pixel Shaders version %d.%d", 4, 0); CRenderer::ChangeGeomInstancingThreshold(); // to get log printout and to set the internal value (vendor dependent) m_Features |= RFT_HW_SM20 | RFT_HW_SM2X | RFT_HW_SM30; // Force the Z targets to be 16-bit float if (!m_bDeviceSupportsR32FRendertarget) { CTexture::s_eTFZ = eTF_R16F; } if (!gcpRendD3D->UseHalfFloatRenderTargets()) { CTexture::s_eTFZ = eTF_R16U; } // Note: Not rolling this into the if statement above in case s_eTFZ is set to R16F on initialization if (CTexture::s_eTFZ != eTF_R32F) { CRenderer::CV_r_CBufferUseNativeDepth = 0; //0=disable } if (!m_bDeviceSupportsInstancing) { _SetVar("r_GeomInstancing", 0); } const char* str = NULL; if (m_Features & RFT_HW_SM50) { str = "SM.5.0"; } else if (m_Features & RFT_HW_SM40) { str = "SM.4.0"; } else { assert(0); } iLog->Log(" Shader model usage: '%s'", str); } else { // force certain features during shader cache gen mode m_Features |= RFT_HW_SM20 | RFT_HW_SM2X | RFT_HW_SM30; m_bDeviceSupportsFP16Filter = true; #if defined(ENABLE_NULL_D3D11DEVICE) m_Device = new NullD3D11Device; D3DDeviceContext* pContext = NULL; #if defined(DEVICE_SUPPORTS_D3D11_3) GetDevice().GetImmediateContext3(&pContext); #elif defined(DEVICE_SUPPORTS_D3D11_2) GetDevice().GetImmediateContext2(&pContext); #elif defined(DEVICE_SUPPORTS_D3D11_1) GetDevice().GetImmediateContext1(&pContext); #else GetDevice().GetImmediateContext(&pContext); #endif m_DeviceContext = pContext; #endif } iLog->Log(" *****************************************"); iLog->Log(" "); iLog->Log("Init Shaders"); // if (!(GetFeatures() & (RFT_HW_PS2X | RFT_HW_PS30))) // SetShaderQuality(eST_All, eSQ_Low); // Quality console variables -------------------------------------- #define QUALITY_VAR(name) { ICVar* pVar = iConsole->Register("q_Shader"#name, &m_cEF.m_ShaderProfiles[(int)eST_##name].m_iShaderProfileQuality, 1, \ 0, CVARHELP("Defines the shader quality of "#name "\nUsage: q_Shader"#name " 0=low/1=med/2=high/3=very high (default)"), OnQShaderChange_Shader##name); \ OnQShaderChange_Shader##name(pVar); \ iLog->Log(" %s shader quality: %s", #name, sGetSQuality("q_Shader"#name)); } // clamp for lowspec QUALITY_VAR(General); QUALITY_VAR(Metal); QUALITY_VAR(Glass); QUALITY_VAR(Vegetation); QUALITY_VAR(Ice); QUALITY_VAR(Terrain); QUALITY_VAR(Shadow); QUALITY_VAR(Water); QUALITY_VAR(FX); QUALITY_VAR(PostProcess); QUALITY_VAR(HDR); QUALITY_VAR(Sky); #undef QUALITY_VAR ICVar* pVar = REGISTER_INT_CB("q_Renderer", 3, 0, "Defines the quality of Renderer\nUsage: q_Renderer 0=low/1=med/2=high/3=very high (default)", OnQShaderChange_Renderer); OnQShaderChange_Renderer(pVar); // clamp for lowspec, report renderer current value iLog->Log("Render quality: %s", sGetSQuality("q_Renderer")); REGISTER_COMMAND("q_Quality", &Command_Quality, 0, "If called with a parameter it sets the quality of all q_.. variables\n" "otherwise it prints their current state\n" "Usage: q_Quality [0=low/1=med/2=high/3=very high]"); REGISTER_COMMAND("r_ColorGradingChartImage", &Command_ColorGradingChartImage, 0, "If called with a parameter it loads a color chart image. This image will overwrite\n" " the dynamic color chart blending result and be used during post processing instead.\n" "If called with no parameter it displays the name of the previously loaded chart.\n" "To reset a previously loaded chart call r_ColorGradingChartImage 0.\n" "Usage: r_ColorGradingChartImage [path of color chart image/reset]"); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_7 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(OPENGL) && !DXGL_FULL_EMULATION && !defined(CRY_USE_METAL) if (!m_pRT->IsRenderThread()) { DXGLUnbindDeviceContext(&GetDeviceContext(), !CV_r_multithreaded); } #endif //defined(OPENGL) && !DXGL_FULL_EMULATION if (!bShaderCacheGen) { m_pRT->RC_Init(); } if (!g_shaderGeneralHeap) { g_shaderGeneralHeap = CryGetIMemoryManager()->CreateGeneralExpandingMemoryHeap(4 * 1024 * 1024, 0, "Shader General"); } m_cEF.mfInit(); CWaterRipples::CreatePhysCallbacks(); if (!IsEditorMode() && !IsShaderCacheGenMode()) { m_pRT->RC_PrecacheDefaultShaders(); } //PostInit(); #if defined(WIN32) // Initialize the set of connected monitors HandleMessage(0, WM_DEVICECHANGE, 0, 0, 0); m_bDisplayChanged = false; #endif m_bInitialized = true; // Cry_memcheck(); if (!bShaderCacheGen) { #if !defined(AZ_PLATFORM_LINUX) // create the D3D implementation of the GPU particle system. m_gpuParticleEngine = new CD3DGPUParticleEngine(); #else AZ_Warning("Rendering", false, "GPU Particles not supported on Linux"); #endif } // Success, return the window handle return (m_hWnd); } //============================================================================= int CD3D9Renderer::EnumAAFormats(SAAFormat* formats) { #if defined(SUPPORT_DEVICE_INFO) int numFormats = 0; for (unsigned int i = 1; i <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++i) { unsigned int maxQuality; if (SUCCEEDED(m_devInfo.Device()->CheckMultisampleQualityLevels(m_devInfo.SwapChainDesc().BufferDesc.Format, i, &maxQuality)) && maxQuality > 0) { if (formats) { formats[numFormats].nSamples = i; formats[numFormats].nQuality = 0; formats[numFormats].szDescr[0] = 0; } ++numFormats; } } return numFormats; #else // #if defined(SUPPORT_DEVICE_INFO) return 0; #endif } int CD3D9Renderer::GetAAFormat(TArray& Formats) { int nNums = EnumAAFormats(NULL); if (nNums > 0) { Formats.resize(nNums); EnumAAFormats(&Formats[0]); } for (unsigned int i = 0; i < Formats.Num(); i++) { if (CV_r_msaa_samples == Formats[i].nSamples && CV_r_msaa_quality == Formats[i].nQuality) { return (int) i; } } return -1; } bool CD3D9Renderer::CheckMSAAChange() { bool bChanged = false; if (CV_r_msaa != m_MSAA || (CV_r_msaa && (m_MSAA_quality != CV_r_msaa_quality || m_MSAA_samples != CV_r_msaa_samples))) { if (CV_r_msaa && (m_hwTexFormatSupport.m_FormatR16G16B16A16.bCanMultiSampleRT || m_hwTexFormatSupport.m_FormatR16G16.bCanMultiSampleRT)) { CTexture::s_eTFZ = eTF_R32F; TArray Formats; int nNum = GetAAFormat(Formats); if (nNum < 0) { iLog->Log(" MSAA: Requested mode not supported\n"); _SetVar("r_MSAA", 0); m_MSAA = 0; } else { iLog->Log(" MSAA: Enabled %d samples (quality level %d)", Formats[nNum].nSamples, Formats[nNum].nQuality); if (Formats[nNum].nQuality != m_MSAA_quality || Formats[nNum].nSamples != m_MSAA_samples) { bChanged = true; _SetVar("r_MSAA_quality", Formats[nNum].nQuality); _SetVar("r_MSAA_samples", Formats[nNum].nSamples); } else if (!m_MSAA) { bChanged = true; } } } else { CTexture::s_eTFZ = eTF_R32F; bChanged = true; iLog->Log(" MSAA: Disabled"); } m_MSAA = CV_r_msaa; m_MSAA_quality = CV_r_msaa_quality; m_MSAA_samples = CV_r_msaa_samples; } return bChanged; } bool CD3D9Renderer::CheckSSAAChange() { const int width = m_CVWidth ? m_CVWidth->GetIVal() : m_width; const int height = m_CVHeight ? m_CVHeight->GetIVal() : m_height; int numSSAASamples = 1; if (width > 0 && height > 0) { const int maxSamples = min(m_MaxTextureSize / width, m_MaxTextureSize / height); numSSAASamples = clamp_tpl(CV_r_Supersampling, 1, maxSamples); } if (m_numSSAASamples != numSSAASamples) { m_numSSAASamples = numSSAASamples; return true; } return false; } //========================================================================== void CD3D9Renderer::InitAMDAPI() { #if defined (WIN32) AGSReturnCode status = AGSInit(); iLog->Log("AGS: AMD GPU Services API init %s (%d)", status == AGS_SUCCESS ? "ok" : "failed", status); m_bVendorLibInitialized = status == AGS_SUCCESS; if (!m_bVendorLibInitialized) { return; } AGSDriverVersionInfoStruct driverInfo = {}; status = AGSDriverGetVersionInfo(&driverInfo); if (status != AGS_SUCCESS) { iLog->LogError("AGS: Unable to get driver version (%d)", status); } else { iLog->Log("AGS: Catalyst Version: %s Driver Version: %s", driverInfo.strCatalystVersion, driverInfo.strDriverVersion); } int outputIndex = 0; #if defined (SUPPORT_DEVICE_INFO) outputIndex = (int)m_devInfo.OutputIndex(); #else if (AGSGetDefaultDisplayIndex(&outputIndex) != AGS_SUCCESS) { outputIndex = 0; } #endif m_nGPUs = 1; int numGPUs = 1; status = AGSCrossfireGetGPUCount(outputIndex, &numGPUs); if (status != AGS_SUCCESS) { iLog->LogError("AGS: Unable to get crossfire info (%d)", status); } else { m_nGPUs = numGPUs; iLog->Log("AGS: Multi GPU count = %d", numGPUs); } #endif // defined(WIN32) } void CD3D9Renderer::InitNVAPI() { #if defined(WIN32) && !defined(OPENGL) NvAPI_Status stat = NvAPI_Initialize(); iLog->Log("NVAPI: API init %s (%d)", stat ? "failed" : "ok", stat); m_bVendorLibInitialized = stat == 0; if (!m_bVendorLibInitialized) { return; } NvU32 version2; char branchVersion[NVAPI_SHORT_STRING_MAX]; NvAPI_Status status = NvAPI_SYS_GetDriverAndBranchVersion(&version2, branchVersion); if (status != NVAPI_OK) { iLog->LogError("NVAPI: Unable to get driver version (%d)", status); } SetNvidiaDriverVersion(version2); // enumerate displays for (int i = 0; i < NVAPI_MAX_DISPLAYS; ++i) { NvDisplayHandle displayHandle; status = NvAPI_EnumNvidiaDisplayHandle(i, &displayHandle); if (status != NVAPI_OK) { break; } } m_nGPUs = 1; // check SLI state to get number of GPUs available for rendering NV_GET_CURRENT_SLI_STATE sliState; sliState.version = NV_GET_CURRENT_SLI_STATE_VER; D3DDevice* device = NULL; # if defined(DIRECT3D10) device = &GetDevice(); # elif defined(DIRECT3D9) device = m_pd3dDevice; # endif status = NvAPI_D3D_GetCurrentSLIState(device, &sliState); if (status != NVAPI_OK) { iLog->LogError("NVAPI: Unable to get SLI state (%d)", status); } else { m_nGPUs = sliState.numAFRGroups; if (m_nGPUs < 2) { iLog->Log("NVAPI: Single GPU system"); } else { m_nGPUs = min((int)m_nGPUs, 31); iLog->Log("NVAPI: System configured as SLI: %d GPU(s) for rendering", m_nGPUs); } } m_bDeviceSupports_NVDBT = 1; iLog->Log("NVDBT supported"); #endif // defined(WIN32) } bool CD3D9Renderer::SetRes() { LOADING_TIME_PROFILE_SECTION; ChangeLog(); m_pixelAspectRatio = 1.0f; /////////////////////////////////////////////////////////////////// #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_8 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(IOS) || defined(APPLETV) || defined(ANDROID) m_bFullScreen = true; if (!m_devInfo.CreateDevice(false, m_width, m_height, m_backbufferWidth, m_backbufferHeight, m_zbpp, OnD3D11CreateDevice, CreateWindowCallback)) { return false; } m_devInfo.SyncInterval() = m_VSync ? 1 : 0; OnD3D11PostCreateDevice(m_devInfo.Device()); AdjustWindowForChange(); CreateContext(m_hWnd); #elif defined(WIN32) || defined(APPLE) || defined(LINUX) UnSetRes(); int width = m_width; int height = m_height; if (IsEditorMode()) { // Note: Editor is a special case, m_backbufferWidth needs to be the same as m_width width = m_deskwidth; height = m_deskheight; } // DirectX9 and DirectX10 device creating #if defined(SUPPORT_DEVICE_INFO) if (m_devInfo.CreateDevice(!m_bFullScreen, width, height, m_backbufferWidth, m_backbufferHeight, m_zbpp, OnD3D11CreateDevice, CreateWindowCallback)) { m_devInfo.SyncInterval() = m_VSync ? 1 : 0; } else { return false; } OnD3D11PostCreateDevice(m_devInfo.Device()); #endif AdjustWindowForChange(); CreateContext(m_hWnd); #else #error UNKNOWN RENDER DEVICE PLATFORM #endif m_DevBufMan.Init(); m_pStereoRenderer->InitDeviceAfterD3D(); return true; } bool SPixFormat::CheckSupport(D3DFormat Format, const char* szDescr, ETexture_Usage eTxUsage) { bool bRes = true; CD3D9Renderer* rd = gcpRendD3D; UINT nOptions; HRESULT hr = gcpRendD3D->GetDevice().CheckFormatSupport(Format, &nOptions); if (SUCCEEDED(hr)) { if (nOptions & (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE)) { bool canAutoGenMips = (nOptions & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) != 0; bool canReadSRGB = CTexture::IsDeviceFormatSRGBReadable(Format); // TODO: check if need to allow other compressed formats to stay here formats here too? // Adding PVRTC format here improved the picture on iOS device. bool bCanMips = true; Init(); DeviceFormat = Format; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_9 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else MaxWidth = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; MaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; #endif Desc = szDescr; BytesPerBlock = CTexture::BytesPerBlock(CTexture::TexFormatFromDeviceFormat(Format)); bCanDS = (nOptions & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0; bCanRT = (nOptions & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0; bCanMultiSampleRT = (nOptions & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0; bCanMips = (nOptions & D3D11_FORMAT_SUPPORT_MIP) != 0; bCanMipsAutoGen = (nOptions & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN) != 0; bCanGather = (nOptions & D3D11_FORMAT_SUPPORT_SHADER_GATHER) != 0; bCanGatherCmp = (nOptions & D3D11_FORMAT_SUPPORT_SHADER_GATHER_COMPARISON) != 0; bCanBlend = (nOptions & D3D11_FORMAT_SUPPORT_BLENDABLE) != 0; bCanReadSRGB = canReadSRGB; if (bCanDS || bCanRT || bCanGather || bCanBlend || bCanReadSRGB || bCanMips) { iLog->Log(" %s%s%s%s%s%s%s%s%s%s", szDescr, bCanMips ? ", mips" : "", bCanMipsAutoGen ? " (autogen)" : "", bCanReadSRGB ? ", sRGB" : "", bCanBlend ? ", blend" : "", bCanDS ? ", DS" : "", bCanRT ? ", RT" : "", bCanMultiSampleRT ? " (multi-sampled)" : "", bCanGather ? ", gather" : "", bCanGatherCmp ? " (comparable)" : "" ); } else { iLog->Log(" %s", szDescr); } Next = rd->m_hwTexFormatSupport.m_FirstPixelFormat; rd->m_hwTexFormatSupport.m_FirstPixelFormat = this; } else { bRes = false; } } else { bRes = false; } return bRes; } void SPixFormatSupport::CheckFormatSupport() { iLog->Log("Using pixel texture formats:"); m_FirstPixelFormat = NULL; m_FormatR8G8B8A8S.CheckSupport(DXGI_FORMAT_R8G8B8A8_SNORM, "R8G8B8A8S"); m_FormatR8G8B8A8.CheckSupport(DXGI_FORMAT_R8G8B8A8_UNORM, "R8G8B8A8"); //m_FormatR1.CheckSupport(DXGI_FORMAT_R1_UNORM, "R1"); m_FormatA8.CheckSupport(DXGI_FORMAT_A8_UNORM, "A8"); m_FormatR8.CheckSupport(DXGI_FORMAT_R8_UNORM, "R8"); m_FormatR8S.CheckSupport(DXGI_FORMAT_R8_SNORM, "R8S"); m_FormatR16.CheckSupport(DXGI_FORMAT_R16_UNORM, "R16"); m_FormatR16U.CheckSupport(DXGI_FORMAT_R16_UINT, "R16U"); m_FormatR16G16U.CheckSupport(DXGI_FORMAT_R16G16_UINT, "R16G16U"); m_FormatR10G10B10A2UI.CheckSupport(DXGI_FORMAT_R10G10B10A2_UINT, "R10G10B10A2UI"); m_FormatR16F.CheckSupport(DXGI_FORMAT_R16_FLOAT, "R16F"); m_FormatR32F.CheckSupport(DXGI_FORMAT_R32_FLOAT, "R32F"); m_FormatR8G8.CheckSupport(DXGI_FORMAT_R8G8_UNORM, "R8G8"); m_FormatR8G8S.CheckSupport(DXGI_FORMAT_R8G8_SNORM, "R8G8S"); m_FormatR16G16.CheckSupport(DXGI_FORMAT_R16G16_UNORM, "R16G16"); m_FormatR16G16S.CheckSupport(DXGI_FORMAT_R16G16_SNORM, "R16G16S"); m_FormatR16G16F.CheckSupport(DXGI_FORMAT_R16G16_FLOAT, "R16G16F"); m_FormatR11G11B10F.CheckSupport(DXGI_FORMAT_R11G11B10_FLOAT, "R11G11B10F"); m_FormatR10G10B10A2.CheckSupport(DXGI_FORMAT_R10G10B10A2_UNORM, "R10G10B10A2"); m_FormatR16G16B16A16.CheckSupport(DXGI_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16"); m_FormatR16G16B16A16S.CheckSupport(DXGI_FORMAT_R16G16B16A16_SNORM, "R16G16B16A16S"); m_FormatR16G16B16A16F.CheckSupport(DXGI_FORMAT_R16G16B16A16_FLOAT, "R16G16B16A16F"); m_FormatR32G32B32A32F.CheckSupport(DXGI_FORMAT_R32G32B32A32_FLOAT, "R32G32B32A32F"); m_FormatBC1.CheckSupport(DXGI_FORMAT_BC1_UNORM, "BC1"); m_FormatBC2.CheckSupport(DXGI_FORMAT_BC2_UNORM, "BC2"); m_FormatBC3.CheckSupport(DXGI_FORMAT_BC3_UNORM, "BC3"); m_FormatBC4U.CheckSupport(DXGI_FORMAT_BC4_UNORM, "BC4"); m_FormatBC4S.CheckSupport(DXGI_FORMAT_BC4_SNORM, "BC4S"); m_FormatBC5U.CheckSupport(DXGI_FORMAT_BC5_UNORM, "BC5"); m_FormatBC5S.CheckSupport(DXGI_FORMAT_BC5_SNORM, "BC5S"); m_FormatBC6UH.CheckSupport(DXGI_FORMAT_BC6H_UF16, "BC6UH"); m_FormatBC6SH.CheckSupport(DXGI_FORMAT_BC6H_SF16, "BC6SH"); m_FormatBC7.CheckSupport(DXGI_FORMAT_BC7_UNORM, "BC7"); m_FormatR9G9B9E5.CheckSupport(DXGI_FORMAT_R9G9B9E5_SHAREDEXP, "R9G9B9E5"); // Depth formats #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_10 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else m_FormatD32FS8.CheckSupport(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, "R32FX8T"); m_FormatD32F.CheckSupport(DXGI_FORMAT_R32_TYPELESS, "R32T"); m_FormatD24S8.CheckSupport(DXGI_FORMAT_R24G8_TYPELESS, "R24G8T"); m_FormatD16.CheckSupport(DXGI_FORMAT_R16_TYPELESS, "R16T"); #endif m_FormatB5G6R5.CheckSupport(DXGI_FORMAT_B5G6R5_UNORM, "B5G6R5"); m_FormatB5G5R5.CheckSupport(DXGI_FORMAT_B5G5R5A1_UNORM, "B5G5R5"); // m_FormatB4G4R4A4.CheckSupport(DXGI_FORMAT_B4G4R4A4_UNORM, "B4G4R4A4"); m_FormatB8G8R8A8.CheckSupport(DXGI_FORMAT_B8G8R8A8_UNORM, "B8G8R8A8"); m_FormatB8G8R8X8.CheckSupport(DXGI_FORMAT_B8G8R8X8_UNORM, "B8G8R8X8"); #if defined(OPENGL) m_FormatEAC_R11.CheckSupport(DXGI_FORMAT_EAC_R11_UNORM, "EAC_R11"); m_FormatEAC_RG11.CheckSupport(DXGI_FORMAT_EAC_RG11_UNORM, "EAC_RG11"); m_FormatETC2.CheckSupport(DXGI_FORMAT_ETC2_UNORM, "ETC2"); m_FormatETC2A.CheckSupport(DXGI_FORMAT_ETC2A_UNORM, "ETC2A"); #endif //defined(OPENGL) #ifdef CRY_USE_METAL m_FormatPVRTC2.CheckSupport(DXGI_FORMAT_PVRTC2_UNORM, "PVRTC2"); m_FormatPVRTC4.CheckSupport(DXGI_FORMAT_PVRTC4_UNORM, "PVRTC4"); #endif #if defined(ANDROID) || defined(CRY_USE_METAL) m_FormatASTC_4x4.CheckSupport(DXGI_FORMAT_ASTC_4x4_UNORM, "ASTC_4x4"); m_FormatASTC_5x4.CheckSupport(DXGI_FORMAT_ASTC_5x4_UNORM, "ASTC_5x4"); m_FormatASTC_5x5.CheckSupport(DXGI_FORMAT_ASTC_5x5_UNORM, "ASTC_5x5"); m_FormatASTC_6x5.CheckSupport(DXGI_FORMAT_ASTC_6x5_UNORM, "ASTC_6x5"); m_FormatASTC_6x6.CheckSupport(DXGI_FORMAT_ASTC_6x6_UNORM, "ASTC_6x6"); m_FormatASTC_8x5.CheckSupport(DXGI_FORMAT_ASTC_8x5_UNORM, "ASTC_8x5"); m_FormatASTC_8x6.CheckSupport(DXGI_FORMAT_ASTC_8x6_UNORM, "ASTC_8x6"); m_FormatASTC_8x8.CheckSupport(DXGI_FORMAT_ASTC_8x8_UNORM, "ASTC_8x8"); m_FormatASTC_10x5.CheckSupport(DXGI_FORMAT_ASTC_10x5_UNORM, "ASTC_10x5"); m_FormatASTC_10x6.CheckSupport(DXGI_FORMAT_ASTC_10x6_UNORM, "ASTC_10x6"); m_FormatASTC_10x8.CheckSupport(DXGI_FORMAT_ASTC_10x8_UNORM, "ASTC_10x8"); m_FormatASTC_10x10.CheckSupport(DXGI_FORMAT_ASTC_10x10_UNORM, "ASTC_10x10"); m_FormatASTC_12x10.CheckSupport(DXGI_FORMAT_ASTC_12x10_UNORM, "ASTC_12x10"); m_FormatASTC_12x12.CheckSupport(DXGI_FORMAT_ASTC_12x12_UNORM, "ASTC_12x12"); #endif } void CD3D9Renderer::GetVideoMemoryUsageStats(size_t& vidMemUsedThisFrame, size_t& vidMemUsedRecently, bool bGetPoolsSizes) { if (bGetPoolsSizes) { vidMemUsedThisFrame = vidMemUsedRecently = (GetTexturesStreamPoolSize() + CV_r_rendertargetpoolsize) * 1024 * 1024; } else { assert(!"CD3D9Renderer::GetVideoMemoryUsageStats() not implemented for this platform yet!"); vidMemUsedThisFrame = vidMemUsedRecently = 0; } } //=========================================================================================== HRESULT CALLBACK CD3D9Renderer::OnD3D11CreateDevice(D3DDevice* pd3dDevice) { LOADING_TIME_PROFILE_SECTION; CD3D9Renderer* rd = gcpRendD3D; rd->m_Device = pd3dDevice; #if defined(SUPPORT_DEVICE_INFO) rd->m_DeviceContext = rd->m_devInfo.Context(); #endif rd->m_Features |= RFT_OCCLUSIONQUERY | RFT_ALLOWANISOTROPIC | RFT_HW_SM20 | RFT_HW_SM2X | RFT_HW_SM30 | RFT_HW_SM40 | RFT_HW_SM50; #if defined(SUPPORT_D3D_DEBUG_RUNTIME) rd->m_d3dDebug.Init(pd3dDevice); rd->m_d3dDebug.Update(ESeverityCombination(CV_d3d11_debugMuteSeverity->GetIVal()), CV_d3d11_debugMuteMsgID->GetString(), CV_d3d11_debugBreakOnMsgID->GetString()); rd->m_bUpdateD3DDebug = false; #endif #if defined(SUPPORT_DEVICE_INFO) rd->BindContextToThread(CryGetCurrentThreadId()); LARGE_INTEGER driverVersion; driverVersion.LowPart = 0; driverVersion.HighPart = 0; rd->m_devInfo.Adapter()->CheckInterfaceSupport(__uuidof(ID3D10Device), &driverVersion); iLog->Log ("D3D Adapter: Description: %ls", rd->m_devInfo.AdapterDesc().Description); iLog->Log ("D3D Adapter: Driver version (UMD): %d.%02d.%02d.%04d", HIWORD(driverVersion.u.HighPart), LOWORD(driverVersion.u.HighPart), HIWORD(driverVersion.u.LowPart), LOWORD(driverVersion.u.LowPart)); iLog->Log ("D3D Adapter: VendorId = 0x%.4X", rd->m_devInfo.AdapterDesc().VendorId); iLog->Log ("D3D Adapter: DeviceId = 0x%.4X", rd->m_devInfo.AdapterDesc().DeviceId); iLog->Log ("D3D Adapter: SubSysId = 0x%.8X", rd->m_devInfo.AdapterDesc().SubSysId); iLog->Log ("D3D Adapter: Revision = %i", rd->m_devInfo.AdapterDesc().Revision); // Vendor-specific initializations and workarounds for driver bugs. { const DXGI_ADAPTER_DESC1& adapterDesc = rd->m_devInfo.AdapterDesc(); rd->m_adapterDescription = AZStd::string::format("%ls", adapterDesc.Description); if (adapterDesc.VendorId == RenderCapabilities::s_gpuVendorIdAMD) { rd->m_Features |= RFT_HW_ATI; rd->InitAMDAPI(); iLog->Log ("D3D Detected: AMD video card"); } else if (adapterDesc.VendorId == RenderCapabilities::s_gpuVendorIdNVIDIA) { rd->m_Features |= RFT_HW_NVIDIA; rd->InitNVAPI(); iLog->Log ("D3D Detected: NVIDIA video card"); } else if (adapterDesc.VendorId == RenderCapabilities::s_gpuVendorIdQualcomm) { rd->m_Features |= RFT_HW_QUALCOMM; iLog->Log ("D3D Detected: Qualcomm video card"); } else if (rd->m_devInfo.AdapterDesc().VendorId == RenderCapabilities::s_gpuVendorIdIntel) { rd->m_Features |= RFT_HW_INTEL; iLog->Log ("D3D Detected: intel video card"); } else if (rd->m_devInfo.AdapterDesc().VendorId == RenderCapabilities::s_gpuVendorIdARM) { rd->m_Features |= RFT_HW_ARM_MALI; iLog->Log ("D3D Detected: ARM (MALI) video card"); } #if defined(OPENGL) && !defined(CRY_USE_METAL) DXGLInitializeIHVSpecifix(); #endif } rd->m_nGPUs = min(rd->m_nGPUs, (uint32)MAX_GPU_NUM); #endif CryLogAlways("Active GPUs: %i", rd->m_nGPUs); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_11 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else rd->m_NumResourceSlots = D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT; rd->m_NumSamplerSlots = D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; rd->m_MaxAnisotropyLevel = min(D3D11_REQ_MAXANISOTROPY, CRenderer::CV_r_texmaxanisotropy); #endif #if defined(WIN32) || defined(WIN64) HWND hWndDesktop = GetDesktopWindow(); HDC dc = GetDC(hWndDesktop); uint16 gamma[3][256]; if (GetDeviceGammaRamp(dc, gamma)) { rd->m_Features |= RFT_HWGAMMA; } ReleaseDC(hWndDesktop, dc); #endif // For safety, lots of drivers don't handle tiny texture sizes too tell. #if defined(SUPPORT_DEVICE_INFO) && !defined(CRY_USE_METAL) rd->m_MaxTextureMemory = rd->m_devInfo.AdapterDesc().DedicatedVideoMemory; #else rd->m_MaxTextureMemory = 256 * 1024 * 1024; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_12 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #elif defined(IOS) rd->m_MaxTextureMemory = 1024 * 1024 * 1024; #endif #endif if (CRenderer::CV_r_TexturesStreamPoolSize <= 0) { CRenderer::CV_r_TexturesStreamPoolSize = (int)(rd->m_MaxTextureMemory / 1024.0f / 1024.0f * 0.75f); } #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_13 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else rd->m_MaxTextureSize = D3D11_REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION; rd->m_bDeviceSupportsInstancing = true; #endif if (rd->m_bDeviceSupportsVertexTexture = (rd->m_Features & RFT_HW_SM30) != 0) { rd->m_Features |= RFT_HW_VERTEXTEXTURES; } #if defined(CRY_USE_METAL) || (defined(OPENGL_ES)) // METAL Supports R32 RTs but it doesn't support blending for it. Cryengine uses blending to fix up depth. // Disable R32 RT for metal for now. // Qualcomm's OpenGL ES 3.0 driver does not support R32F render targets. Disabling for all OpenGL ES 3.0 versions for the time being. // When bound as a render target, we get this error: // W/Adreno-ES20(12623): : GL_INVALID_OPERATION //R32 depth render targets are showing instability on Mali GPUs. For stability reasons we are forcing R16 render targets across all Android devices. rd->m_bDeviceSupportsR32FRendertarget = false; #else rd->m_bDeviceSupportsR32FRendertarget = true; #endif #if defined(CRY_USE_METAL) || defined(OPENGL) D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS computeShadersSupport; HRESULT result = rd->GetDevice().CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &computeShadersSupport, sizeof(computeShadersSupport)); if (result == S_OK && computeShadersSupport.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x == TRUE) { rd->m_Features |= RFT_COMPUTE_SHADERS; } #else rd->m_Features |= RFT_COMPUTE_SHADERS; #endif if (RenderCapabilities::SupportsStructuredBuffer(EShaderStage_Vertex)) { rd->m_Features |= RFT_HW_VERTEX_STRUCTUREDBUF; } #if defined(DIRECT3D10) && !defined(OPENGL_ES) && !defined(CRY_USE_METAL) rd->m_bDeviceSupportsGeometryShaders = (rd->m_Features & RFT_HW_SM40) != 0; #else rd->m_bDeviceSupportsGeometryShaders = false; #endif #if defined(DIRECT3D10) && !defined(OPENGL) && !defined(CRY_USE_METAL) rd->m_bDeviceSupportsTessellation = (rd->m_Features & RFT_HW_SM50) != 0; #else rd->m_bDeviceSupportsTessellation = false; #endif rd->m_Features |= RFT_OCCLUSIONTEST; rd->m_bUseWaterTessHW = CV_r_WaterTessellationHW != 0 && rd->m_bDeviceSupportsTessellation; PREFAST_SUPPRESS_WARNING(6326); //not a constant vs constant comparison on Win32/Win64 rd->m_bUseSilhouettePOM = CV_r_SilhouettePOM != 0; rd->m_bUseSpecularAntialiasing = CV_r_SpecularAntialiasing != 0; CV_r_DeferredShadingAmbientSClear = !(rd->m_Features & RFT_HW_NVIDIA) ? 0 : CV_r_DeferredShadingAmbientSClear; // Handle the texture formats we need. { // Find the needed texture formats. rd->m_hwTexFormatSupport.CheckFormatSupport(); rd->m_bDeviceSupportsFP16Separate = false; rd->m_bDeviceSupportsFP16Filter = true; #ifdef CRY_USE_METAL rd->m_FormatPVRTC2.CheckSupport(DXGI_FORMAT_PVRTC2_UNORM, "PVRTC2"); rd->m_FormatPVRTC4.CheckSupport(DXGI_FORMAT_PVRTC4_UNORM, "PVRTC4"); #endif #if defined(ANDROID) || defined(CRY_USE_METAL) rd->m_FormatASTC_4x4.CheckSupport(DXGI_FORMAT_ASTC_4x4_UNORM, "ASTC_4x4"); rd->m_FormatASTC_5x4.CheckSupport(DXGI_FORMAT_ASTC_5x4_UNORM, "ASTC_5x4"); rd->m_FormatASTC_5x5.CheckSupport(DXGI_FORMAT_ASTC_5x5_UNORM, "ASTC_5x5"); rd->m_FormatASTC_6x5.CheckSupport(DXGI_FORMAT_ASTC_6x5_UNORM, "ASTC_6x5"); rd->m_FormatASTC_6x6.CheckSupport(DXGI_FORMAT_ASTC_6x6_UNORM, "ASTC_6x6"); rd->m_FormatASTC_8x5.CheckSupport(DXGI_FORMAT_ASTC_8x5_UNORM, "ASTC_8x5"); rd->m_FormatASTC_8x6.CheckSupport(DXGI_FORMAT_ASTC_8x6_UNORM, "ASTC_8x6"); rd->m_FormatASTC_8x8.CheckSupport(DXGI_FORMAT_ASTC_8x8_UNORM, "ASTC_8x8"); rd->m_FormatASTC_10x5.CheckSupport(DXGI_FORMAT_ASTC_10x5_UNORM, "ASTC_10x5"); rd->m_FormatASTC_10x6.CheckSupport(DXGI_FORMAT_ASTC_10x6_UNORM, "ASTC_10x6"); rd->m_FormatASTC_10x8.CheckSupport(DXGI_FORMAT_ASTC_10x8_UNORM, "ASTC_10x8"); rd->m_FormatASTC_10x10.CheckSupport(DXGI_FORMAT_ASTC_10x10_UNORM, "ASTC_10x10"); rd->m_FormatASTC_12x10.CheckSupport(DXGI_FORMAT_ASTC_12x10_UNORM, "ASTC_12x10"); rd->m_FormatASTC_12x12.CheckSupport(DXGI_FORMAT_ASTC_12x12_UNORM, "ASTC_12x12"); #endif if (rd->m_hwTexFormatSupport.m_FormatBC1.IsValid() || rd->m_hwTexFormatSupport.m_FormatBC2.IsValid() || rd->m_hwTexFormatSupport.m_FormatBC3.IsValid()) { rd->m_Features |= RFT_COMPRESSTEXTURE; } } rd->m_Features |= RFT_HW_HDR; rd->m_nHDRType = 1; rd->m_FullResRect.right = rd->m_width; rd->m_FullResRect.bottom = rd->m_height; #if defined(WIN32) || defined(WIN64) || defined(APPLE) || defined(LINUX) || defined(CREATE_DEVICE_ON_MAIN_THREAD) rd->m_pRT->RC_SetViewport(0, 0, rd->m_width, rd->m_height); #else rd->RT_SetViewport(0, 0, rd->m_width, rd->m_height); #endif rd->m_MainViewport.nX = 0; rd->m_MainViewport.nY = 0; rd->m_MainViewport.nWidth = rd->m_width; rd->m_MainViewport.nHeight = rd->m_height; return S_OK; } HRESULT CALLBACK CD3D9Renderer::OnD3D11PostCreateDevice(D3DDevice* pd3dDevice) { LOADING_TIME_PROFILE_SECTION; CD3D9Renderer* rd = gcpRendD3D; HRESULT hr; #if defined(SUPPORT_DEVICE_INFO) rd->BindContextToThread(CryGetCurrentThreadId()); rd->m_DeviceContext = rd->m_devInfo.Context(); rd->m_pBackBuffer = rd->m_devInfo.BackbufferRTV(); rd->m_pBackBuffers = rd->m_devInfo.BackbufferRTVs(); rd->m_pSwapChain = rd->m_devInfo.SwapChain(); rd->m_pCurrentBackBufferIndex = rd->GetCurrentBackBufferIndex(rd->m_pSwapChain); #endif void* pBackBuf; hr = rd->m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &pBackBuf); if (FAILED(hr)) { return hr; } ID3D11Texture2D* pBackBuffer = (ID3D11Texture2D*)pBackBuf; D3D11_TEXTURE2D_DESC backBufferSurfaceDesc; pBackBuffer->GetDesc(&backBufferSurfaceDesc); ZeroMemory(&rd->m_d3dsdBackBuffer, sizeof(DXGI_SURFACE_DESC)); rd->m_d3dsdBackBuffer.Width = (UINT) backBufferSurfaceDesc.Width; rd->m_d3dsdBackBuffer.Height = (UINT) backBufferSurfaceDesc.Height; #if defined(SUPPORT_DEVICE_INFO) rd->m_d3dsdBackBuffer.Format = backBufferSurfaceDesc.Format; rd->m_d3dsdBackBuffer.SampleDesc = backBufferSurfaceDesc.SampleDesc; rd->m_ZFormat = rd->m_devInfo.AutoDepthStencilFmt(); #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_14 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif SAFE_RELEASE(pBackBuffer); if (FAILED(hr)) { return hr; } // Collect depth stencil parameters D3D11_TEXTURE2D_DESC dsTextureDesc; dsTextureDesc.MipLevels = 1; dsTextureDesc.ArraySize = 1; dsTextureDesc.Format = rd->m_ZFormat; dsTextureDesc.SampleDesc = rd->m_d3dsdBackBuffer.SampleDesc; dsTextureDesc.Usage = D3D11_USAGE_DEFAULT; dsTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; dsTextureDesc.CPUAccessFlags = 0; dsTextureDesc.MiscFlags = 0; D3D11_DEPTH_STENCIL_VIEW_DESC dsViewDesc; dsViewDesc.Format = CTexture::ConvertToDepthStencilFmt(dsTextureDesc.Format); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_15 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else dsViewDesc.Flags = 0; #endif dsViewDesc.ViewDimension = dsTextureDesc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; dsViewDesc.Texture2D.MipSlice = 0; const float clearDepth = CRenderer::CV_r_ReverseDepth ? 0.f : 1.f; const uint clearStencil = 1; const FLOAT clearValues[4] = { clearDepth, FLOAT(clearStencil) }; int nDepthBufferWidth = rd->IsEditorMode() ? rd->m_d3dsdBackBuffer.Width : rd->m_width; int nDepthBufferHeight = rd->IsEditorMode() ? rd->m_d3dsdBackBuffer.Height : rd->m_height; // Create the depth stencil buffer for scene rendering SAFE_RELEASE(rd->m_pZTexture); SAFE_RELEASE(rd->m_pZBuffer); dsTextureDesc.Width = nDepthBufferWidth; dsTextureDesc.Height = nDepthBufferHeight; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_16 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif hr = rd->m_DevMan.CreateD3D11Texture2D(&dsTextureDesc, clearValues, NULL, &rd->m_pZTexture, "DepthBuffer"); if (FAILED(hr)) { #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_17 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif return hr; } hr = rd->GetDevice().CreateDepthStencilView(rd->m_pZTexture, &dsViewDesc, &rd->m_pZBuffer); if (FAILED(hr)) { return hr; } rd->GetDeviceContext().ClearDepthStencilView(rd->m_pZBuffer, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, clearDepth, clearStencil); // Create the native resolution depth stencil buffer for overlay rendering if needed SAFE_RELEASE(rd->m_pNativeZTexture); SAFE_RELEASE(rd->m_pNativeZBuffer); if (!rd->IsEditorMode() && (gcpRendD3D->GetOverlayWidth() != dsTextureDesc.Width || gcpRendD3D->GetOverlayHeight() != dsTextureDesc.Height)) { dsTextureDesc.Width = gcpRendD3D->GetOverlayWidth(); dsTextureDesc.Height = gcpRendD3D->GetOverlayHeight(); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_18 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif hr = rd->m_DevMan.CreateD3D11Texture2D(&dsTextureDesc, clearValues, NULL, &rd->m_pNativeZTexture, "DepthBuffer"); if (FAILED(hr)) { return hr; } hr = rd->GetDevice().CreateDepthStencilView(rd->m_pNativeZTexture, &dsViewDesc, &rd->m_pNativeZBuffer); if (FAILED(hr)) { return hr; } rd->GetDeviceContext().ClearDepthStencilView(rd->m_pNativeZBuffer, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, clearDepth, clearStencil); } else { rd->m_pNativeZTexture = rd->m_pZTexture; rd->m_pNativeZBuffer = rd->m_pZBuffer; rd->m_pNativeZTexture->AddRef(); rd->m_pNativeZBuffer->AddRef(); } rd->m_DepthBufferOrig.pTex = nullptr; rd->m_DepthBufferOrig.pTarget = rd->m_pZTexture; rd->m_DepthBufferOrig.pSurf = rd->m_pZBuffer; rd->m_pZBuffer->AddRef(); rd->m_DepthBufferOrigMSAA.pTex = nullptr; rd->m_DepthBufferOrigMSAA.pTarget = rd->m_pZTexture; rd->m_DepthBufferOrigMSAA.pSurf = rd->m_pZBuffer; rd->m_pZBuffer->AddRef(); rd->m_DepthBufferNative.pTex = nullptr; rd->m_DepthBufferNative.pTarget = rd->m_pNativeZTexture; rd->m_DepthBufferNative.pSurf = rd->m_pNativeZBuffer; rd->m_pNativeZBuffer->AddRef(); rd->m_nRTStackLevel[0] = 0; if (rd->m_d3dsdBackBuffer.Width == rd->m_nativeWidth && rd->m_d3dsdBackBuffer.Height == rd->m_nativeHeight) { rd->m_RTStack[0][0].m_pDepth = rd->m_pNativeZBuffer; rd->m_RTStack[0][0].m_pSurfDepth = &rd->m_DepthBufferNative; } else { rd->m_RTStack[0][0].m_pDepth = NULL; rd->m_RTStack[0][0].m_pSurfDepth = NULL; } rd->m_RTStack[0][0].m_pTarget = rd->m_pBackBuffer; rd->m_RTStack[0][0].m_Width = rd->m_d3dsdBackBuffer.Width; rd->m_RTStack[0][0].m_Height = rd->m_d3dsdBackBuffer.Height; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_19 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else rd->m_RTStack[0][0].m_bScreenVP = false; #endif rd->m_RTStack[0][0].m_bWasSetRT = false; rd->m_RTStack[0][0].m_bWasSetD = false; rd->m_nMaxRT2Commit = 0; rd->m_pNewTarget[0] = &rd->m_RTStack[0][0]; rd->FX_SetActiveRenderTargets(); for (int i = 0; i < RT_STACK_WIDTH; i++) { rd->m_pNewTarget[i] = &rd->m_RTStack[i][0]; rd->m_pCurTarget[i] = rd->m_pNewTarget[0]->m_pTex; } rd->m_DepthBufferOrig.nWidth = nDepthBufferWidth; rd->m_DepthBufferOrig.nHeight = nDepthBufferHeight; rd->m_DepthBufferOrig.bBusy = true; rd->m_DepthBufferOrig.nFrameAccess = -2; rd->m_DepthBufferOrigMSAA.nWidth = nDepthBufferWidth; rd->m_DepthBufferOrigMSAA.nHeight = nDepthBufferHeight; rd->m_DepthBufferOrigMSAA.bBusy = true; rd->m_DepthBufferOrigMSAA.nFrameAccess = -2; rd->m_DepthBufferNative.nWidth = rd->m_nativeWidth; rd->m_DepthBufferNative.nHeight = rd->m_nativeHeight; rd->m_DepthBufferNative.bBusy = true; rd->m_DepthBufferNative.nFrameAccess = -2; SAFE_RELEASE(rd->m_RP.m_MSAAData.m_pDepthTex); SAFE_RELEASE(rd->m_RP.m_MSAAData.m_pZBuffer); rd->CreateMSAADepthBuffer(); // Create shader bindable depthstencil buffer view and shader resource view. Ideally would be unified into regular texture creation - requires big refactoring SAFE_RELEASE(rd->m_pZBufferReadOnlyDSV); SAFE_RELEASE(rd->m_pZBufferDepthReadOnlySRV); SAFE_RELEASE(rd->m_pZBufferStencilReadOnlySRV); D3DTexture* pDepthStencil = rd->m_DepthBufferOrigMSAA.pTarget; D3D11_TEXTURE2D_DESC descDepthStencil; pDepthStencil->GetDesc(&descDepthStencil); #if defined(SUPPORT_DEVICE_INFO) if (rd->DevInfo().FeatureLevel() >= D3D_FEATURE_LEVEL_11_0) // Read-only depth-stencil supported on 11.0 feature level and above, leave NULL otherwise resulting in no testing #endif //defined(SUPPORT_DEVICE_INFO) { D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; ZeroStruct(descDSV); descDSV.Format = CTexture::ConvertToDepthStencilFmt(descDepthStencil.Format); descDSV.Flags = D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL; descDSV.ViewDimension = (descDepthStencil.SampleDesc.Count > 1) ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = rd->GetDevice().CreateDepthStencilView(pDepthStencil, &descDSV, &rd->m_pZBufferReadOnlyDSV); assert(SUCCEEDED(hr)); } D3DFormat nDepthStencilFormatTypeless = descDepthStencil.Format; if (!CTexture::IsDeviceFormatTypeless(nDepthStencilFormatTypeless)) { nDepthStencilFormatTypeless = CTexture::ConvertToTypelessFmt(nDepthStencilFormatTypeless); } D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; ZeroStruct(SRVDesc); SRVDesc.Format = CTexture::ConvertToShaderResourceFmt(nDepthStencilFormatTypeless); SRVDesc.ViewDimension = (descDepthStencil.SampleDesc.Count > 1) ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; SRVDesc.Texture2D.MipLevels = 1; hr = rd->GetDevice().CreateShaderResourceView(pDepthStencil, &SRVDesc, &rd->m_pZBufferDepthReadOnlySRV); assert(SUCCEEDED(hr)); if (RenderCapabilities::SupportsStencilTextures()) { SRVDesc.Format = CTexture::ConvertToStencilFmt(nDepthStencilFormatTypeless); hr = rd->GetDevice().CreateShaderResourceView(pDepthStencil, &SRVDesc, &rd->m_pZBufferStencilReadOnlySRV); assert(SUCCEEDED(hr)); } #if !defined(_RELEASE) #if defined(WIN32) #define D3DSYSTEM_CPP_USE_PRIVATEDATA #elif defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_20 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #endif #if defined(D3DSYSTEM_CPP_USE_PRIVATEDATA) if (rd->m_pZTexture) { AZStd::string dsvName("$MainDepthStencil"); rd->m_pZTexture->SetPrivateData(WKPDID_D3DDebugObjectName, dsvName.length(), dsvName.c_str()); } if (rd->m_pZBuffer) { AZStd::string srvName("[DSV] $MainDepthStencil"); rd->m_pZBuffer->SetPrivateData(WKPDID_D3DDebugObjectName, srvName.length(), srvName.c_str()); } if (rd->m_pZBufferReadOnlyDSV) { AZStd::string srvName("[DSV] $MainDepthStencil - Read Only"); rd->m_pZBufferReadOnlyDSV->SetPrivateData(WKPDID_D3DDebugObjectName, srvName.length(), srvName.c_str()); } if (rd->m_pZBufferDepthReadOnlySRV) { AZStd::string srvName("[SRV] $MainDepthStencil - Depth Read Only"); rd->m_pZBufferDepthReadOnlySRV->SetPrivateData(WKPDID_D3DDebugObjectName, srvName.length(), srvName.c_str()); } if (rd->m_pZBufferStencilReadOnlySRV) { AZStd::string srvName("[SRV] $MainDepthStencil - Stencil Read Only"); rd->m_pZBufferStencilReadOnlySRV->SetPrivateData(WKPDID_D3DDebugObjectName, srvName.length(), srvName.c_str()); } #endif rd->ReleaseAuxiliaryMeshes(); rd->CreateAuxiliaryMeshes(); #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_21 #if defined(AZ_PLATFORM_XENIA) #include "Xenia/D3DSystem_cpp_xenia.inl" #elif defined(AZ_PLATFORM_PROVO) #include "Provo/D3DSystem_cpp_provo.inl" #elif defined(AZ_PLATFORM_SALEM) #include "Salem/D3DSystem_cpp_salem.inl" #endif #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else D3D11_QUERY_DESC QDesc; QDesc.Query = D3D11_QUERY_EVENT; QDesc.MiscFlags = 0; for (int i = 0; i < 2; ++i) { hr = pd3dDevice->CreateQuery(&QDesc, &rd->m_pQuery[i]); assert(hr == S_OK && rd->m_pQuery[i]); rd->GetDeviceContext().End(rd->m_pQuery[i]); } #endif rd->EF_Restore(); rd->m_bDeviceLost = 0; rd->m_pLastVDeclaration = NULL; #if defined(ENABLE_RENDER_AUX_GEOM) if (rd->m_pRenderAuxGeomD3D && FAILED(hr = rd->m_pRenderAuxGeomD3D->RestoreDeviceObjects())) { return hr; } #endif CHWShader_D3D::mfSetGlobalParams(); if (rd->m_OcclQueries.capacity()) { for (int a = 0; a < MAX_OCCL_QUERIES; a++) { rd->m_OcclQueries[a].Release(); } } { LOADING_TIME_PROFILE_SECTION_NAMED("CD3D9Renderer::OnD3D10PostCreateDevice(): m_OcclQueries"); rd->m_OcclQueries.Reserve(MAX_OCCL_QUERIES); // Lazy initialization on Android due to limited number of queries that we can create. // TODO Linux - This was crashing on Ubuntu, investigate #if !defined(AZ_PLATFORM_ANDROID) && !defined(AZ_PLATFORM_LINUX) for (int a = 0; a < MAX_OCCL_QUERIES; a++) { rd->m_OcclQueries[a].Create(); } #endif } return S_OK; } #if defined(WIN32) // Renderer looks for multi-monitor setup changes and fullscreen key combination bool CD3D9Renderer::HandleMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { switch (message) { case WM_DISPLAYCHANGE: case WM_DEVICECHANGE: { // Count the number of connected display devices bool bHaveMonitorsChanged = true; uint connectedMonitors = 0; EnumDisplayMonitors(NULL, NULL, CountConnectedMonitors, reinterpret_cast(&connectedMonitors)); // Check for changes if (connectedMonitors > m_nConnectedMonitors) { iSystem->GetILog()->LogAlways("[Renderer] A display device has been connected to the system"); } else if (connectedMonitors < m_nConnectedMonitors) { iSystem->GetILog()->LogAlways("[Renderer] A display device has been disconnected from the system"); } else { bHaveMonitorsChanged = false; } // Update state m_nConnectedMonitors = connectedMonitors; m_bDisplayChanged = bHaveMonitorsChanged; } break; case WM_SYSKEYDOWN: { const bool bAlt = (lParam & (1 << 29)) != 0; if (wParam == VK_RETURN && bAlt) // ALT+ENTER { ICVar* pVar = iConsole->GetCVar("r_fullscreen"); if (pVar) { int fullscreen = pVar->GetIVal(); pVar->Set((int)(fullscreen == 0)); // Toggle CVar } } } break; } return false; } #endif // defined(WIN32) #if defined(SUPPORT_DEVICE_INFO_USER_DISPLAY_OVERRIDES) static const char* GetScanlineOrderNaming(DXGI_MODE_SCANLINE_ORDER v) { switch (v) { case DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE: return "progressive"; case DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST: return "interlaced (upper field first)"; case DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST: return "interlaced (lower field first)"; default: return "unspecified"; } } void UserOverrideDisplayProperties(DXGI_MODE_DESC& desc) { if (gRenDev->m_CVFullScreen->GetIVal()) { if (gRenDev->CV_r_overrideRefreshRate > 0) { DXGI_RATIONAL& refreshRate = desc.RefreshRate; if (refreshRate.Denominator) { gEnv->pLog->Log("Overriding refresh rate to %.2f Hz (was %.2f Hz).", (float)gRenDev->CV_r_overrideRefreshRate, (float)refreshRate.Numerator / (float)refreshRate.Denominator); } else { gEnv->pLog->Log("Overriding refresh rate to %.2f Hz (was undefined).", (float)gRenDev->CV_r_overrideRefreshRate); } refreshRate.Numerator = (unsigned int) (gRenDev->CV_r_overrideRefreshRate * 1000.0f); refreshRate.Denominator = 1000; } if (gRenDev->CV_r_overrideScanlineOrder > 0) { DXGI_MODE_SCANLINE_ORDER old = desc.ScanlineOrdering; DXGI_MODE_SCANLINE_ORDER& so = desc.ScanlineOrdering; switch (gRenDev->CV_r_overrideScanlineOrder) { case 2: so = DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST; break; case 3: so = DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST; break; default: so = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE; break; } gEnv->pLog->Log("Overriding scanline order to %s (was %s).", GetScanlineOrderNaming(so), GetScanlineOrderNaming(old)); } } } #endif #include "DeviceInfo.inl" void EnableCloseButton(void* hWnd, bool enabled) { #if defined(WIN32) || defined(WIN64) if (hWnd) { HMENU hMenu = GetSystemMenu((HWND) hWnd, FALSE); if (hMenu) { const unsigned int flags = enabled ? MF_ENABLED : (MF_DISABLED | MF_GRAYED); EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | flags); } } #endif } #if defined(SUPPORT_D3D_DEBUG_RUNTIME) string D3DDebug_GetLastMessage() { return gcpRendD3D->m_d3dDebug.GetLastMessage(); } #endif