You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2981 lines
95 KiB
C++
2981 lines
95 KiB
C++
/*
|
|
* 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 "RenderDll_precompiled.h"
|
|
#include "UnicodeFunctions.h"
|
|
#include "DriverD3D.h"
|
|
#include "WindowsUtils.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
|
|
#define D3DSYSTEM_CPP_SECTION_22 22
|
|
#endif
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_1
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#endif
|
|
|
|
|
|
#include "D3DStereo.h"
|
|
#include "D3DPostProcess.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
|
|
#endif // defined(WIN32)
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_2
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#endif
|
|
|
|
#include "../Common/RenderCapabilities.h"
|
|
#include <AzCore/Utils/Utils.h>
|
|
|
|
#ifdef WIN32
|
|
// Count monitors helper
|
|
static BOOL CALLBACK CountConnectedMonitors([[maybe_unused]] HMONITOR hMonitor, [[maybe_unused]] HDC hDC, [[maybe_unused]] LPRECT pRect, LPARAM opaque)
|
|
{
|
|
uint* count = reinterpret_cast<uint*>(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, [[maybe_unused]] 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<int>(aznumeric_cast<float>(m_width) / (m_CurrContext ? m_CurrContext->m_fPixelScaleX : 1.0f));
|
|
pContext->m_nViewportHeight = aznumeric_cast<int>(aznumeric_cast<float>(m_height) / (m_CurrContext ? m_CurrContext->m_fPixelScaleY : 1.0f));
|
|
pContext->m_fPixelScaleX = aznumeric_cast<float>(std::max(1, SSX));
|
|
pContext->m_fPixelScaleY = aznumeric_cast<float>(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, [[maybe_unused]] 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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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([[maybe_unused]] 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<DXGI_MODE_DESC> 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([[maybe_unused]] unsigned int width, [[maybe_unused]] unsigned int height, [[maybe_unused]] 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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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([[maybe_unused]] gammaramp_t* gamma)
|
|
{
|
|
if (!(GetFeatures() & RFT_HWGAMMA))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if IsCVarConstAccess(constexpr) (bool(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 IsCVarConstAccess(constexpr) (bool(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<ID3D11Texture2D*>(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);
|
|
|
|
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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
|
|
HWND CD3D9Renderer::CreateWindowCallback()
|
|
{
|
|
gcpRendD3D->SetWindow(gcpRendD3D->GetBackbufferWidth(), gcpRendD3D->GetBackbufferHeight(), gcpRendD3D->m_bFullScreen, gcpRendD3D->m_hWnd);
|
|
|
|
return gcpRendD3D->m_hWnd;
|
|
}
|
|
|
|
bool CD3D9Renderer::SetWindow([[maybe_unused]] int width, [[maybe_unused]] int height, [[maybe_unused]] bool fullscreen, [[maybe_unused]] WIN_HWND hWnd)
|
|
{
|
|
LOADING_TIME_PROFILE_SECTION;
|
|
|
|
#if D3DSYSTEM_CPP_TRAIT_SETWINDOW_REGISTERWINDOWMESSAGEHANDLER
|
|
iSystem->RegisterWindowMessageHandler(this);
|
|
m_registeredWindoWHandler = true;
|
|
#endif
|
|
|
|
#if defined(AZ_RESTRICTED_PLATFORM)
|
|
#define AZ_RESTRICTED_SECTION D3DSYSTEM_CPP_SECTION_22
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#endif
|
|
|
|
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
|
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
|
#elif 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<wstring>(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([[maybe_unused]] 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(Ice)
|
|
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([[maybe_unused]] int x, [[maybe_unused]] int y, int width, int height, unsigned int cbpp, int zbpp, int sbits, bool fullscreen, bool isEditor, WIN_HINSTANCE hinst, WIN_HWND Glhwnd, [[maybe_unused]] bool bReInit, [[maybe_unused]] 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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#endif
|
|
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
|
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
|
#elif defined(IOS)
|
|
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 = <UNDEFINED>");
|
|
#endif
|
|
|
|
iLog->Log ("Direct3D driver is creating...");
|
|
iLog->Log ("Crytek Direct3D driver version %4.2f (%s <%s>)", VERSION_D3D, __DATE__, __TIME__);
|
|
|
|
auto projectName = AZ::Utils::GetProjectName();
|
|
cry_strcpy(m_WinTitle, projectName.c_str());
|
|
|
|
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(Ice);
|
|
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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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)
|
|
{
|
|
}
|
|
|
|
// Success, return the window handle
|
|
return (m_hWnd);
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int CD3D9Renderer::EnumAAFormats([[maybe_unused]] 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<SAAFormat>& 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<SAAFormat> 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;
|
|
}
|
|
|
|
//==========================================================================
|
|
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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#endif
|
|
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
|
|
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
|
|
#elif defined(IOS) || 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, [[maybe_unused]] 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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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;
|
|
iLog->Log ("D3D Detected: AMD video card");
|
|
}
|
|
else if (adapterDesc.VendorId == RenderCapabilities::s_gpuVendorIdNVIDIA)
|
|
{
|
|
rd->m_Features |= RFT_HW_NVIDIA;
|
|
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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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): <validate_render_targets:444>: 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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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
|
|
#include AZ_RESTRICTED_FILE(D3DSystem_cpp)
|
|
#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([[maybe_unused]] HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, [[maybe_unused]] 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<LPARAM>(&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([[maybe_unused]] void* hWnd, [[maybe_unused]] 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
|