michael@0: #include "precompiled.h" michael@0: // michael@0: // Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. michael@0: michael@0: #include "libGLESv2/main.h" michael@0: #include "libGLESv2/utilities.h" michael@0: #include "libGLESv2/Buffer.h" michael@0: #include "libGLESv2/ProgramBinary.h" michael@0: #include "libGLESv2/Framebuffer.h" michael@0: #include "libGLESv2/Renderbuffer.h" michael@0: #include "libGLESv2/renderer/Renderer11.h" michael@0: #include "libGLESv2/renderer/RenderTarget11.h" michael@0: #include "libGLESv2/renderer/renderer11_utils.h" michael@0: #include "libGLESv2/renderer/ShaderExecutable11.h" michael@0: #include "libGLESv2/renderer/SwapChain11.h" michael@0: #include "libGLESv2/renderer/Image11.h" michael@0: #include "libGLESv2/renderer/VertexBuffer11.h" michael@0: #include "libGLESv2/renderer/IndexBuffer11.h" michael@0: #include "libGLESv2/renderer/BufferStorage11.h" michael@0: #include "libGLESv2/renderer/VertexDataManager.h" michael@0: #include "libGLESv2/renderer/IndexDataManager.h" michael@0: #include "libGLESv2/renderer/TextureStorage11.h" michael@0: #include "libGLESv2/renderer/Query11.h" michael@0: #include "libGLESv2/renderer/Fence11.h" michael@0: michael@0: #include "libGLESv2/renderer/shaders/compiled/passthrough11vs.h" michael@0: #include "libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h" michael@0: #include "libGLESv2/renderer/shaders/compiled/passthroughrgb11ps.h" michael@0: #include "libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h" michael@0: #include "libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h" michael@0: michael@0: #include "libGLESv2/renderer/shaders/compiled/clear11vs.h" michael@0: #include "libGLESv2/renderer/shaders/compiled/clearsingle11ps.h" michael@0: #include "libGLESv2/renderer/shaders/compiled/clearmultiple11ps.h" michael@0: michael@0: #include "libEGL/Display.h" michael@0: michael@0: #ifdef _DEBUG michael@0: // this flag enables suppressing some spurious warnings that pop up in certain WebGL samples michael@0: // and conformance tests. to enable all warnings, remove this define. michael@0: #define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 michael@0: #endif michael@0: michael@0: namespace rx michael@0: { michael@0: static const DXGI_FORMAT RenderTargetFormats[] = michael@0: { michael@0: DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: DXGI_FORMAT_R8G8B8A8_UNORM michael@0: }; michael@0: michael@0: static const DXGI_FORMAT DepthStencilFormats[] = michael@0: { michael@0: DXGI_FORMAT_UNKNOWN, michael@0: DXGI_FORMAT_D24_UNORM_S8_UINT, michael@0: DXGI_FORMAT_D16_UNORM michael@0: }; michael@0: michael@0: enum michael@0: { michael@0: MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 michael@0: }; michael@0: michael@0: Renderer11::Renderer11(egl::Display *display, HDC hDc) : Renderer(display), mDc(hDc) michael@0: { michael@0: mVertexDataManager = NULL; michael@0: mIndexDataManager = NULL; michael@0: michael@0: mLineLoopIB = NULL; michael@0: mTriangleFanIB = NULL; michael@0: michael@0: mCopyResourcesInitialized = false; michael@0: mCopyVB = NULL; michael@0: mCopySampler = NULL; michael@0: mCopyIL = NULL; michael@0: mCopyVS = NULL; michael@0: mCopyRGBAPS = NULL; michael@0: mCopyRGBPS = NULL; michael@0: mCopyLumPS = NULL; michael@0: mCopyLumAlphaPS = NULL; michael@0: michael@0: mClearResourcesInitialized = false; michael@0: mClearVB = NULL; michael@0: mClearIL = NULL; michael@0: mClearVS = NULL; michael@0: mClearSinglePS = NULL; michael@0: mClearMultiplePS = NULL; michael@0: mClearScissorRS = NULL; michael@0: mClearNoScissorRS = NULL; michael@0: michael@0: mSyncQuery = NULL; michael@0: michael@0: mD3d11Module = NULL; michael@0: mDxgiModule = NULL; michael@0: michael@0: mDeviceLost = false; michael@0: michael@0: mMaxSupportedSamples = 0; michael@0: michael@0: mDevice = NULL; michael@0: mDeviceContext = NULL; michael@0: mDxgiAdapter = NULL; michael@0: mDxgiFactory = NULL; michael@0: michael@0: mDriverConstantBufferVS = NULL; michael@0: mDriverConstantBufferPS = NULL; michael@0: michael@0: mBGRATextureSupport = false; michael@0: michael@0: mIsGeometryShaderActive = false; michael@0: } michael@0: michael@0: Renderer11::~Renderer11() michael@0: { michael@0: release(); michael@0: } michael@0: michael@0: Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) michael@0: { michael@0: ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer11*, renderer)); michael@0: return static_cast(renderer); michael@0: } michael@0: michael@0: #ifndef __d3d11_1_h__ michael@0: #define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081) michael@0: #endif michael@0: michael@0: EGLint Renderer11::initialize() michael@0: { michael@0: if (!initializeCompiler()) michael@0: { michael@0: return EGL_NOT_INITIALIZED; michael@0: } michael@0: michael@0: mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); michael@0: mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); michael@0: michael@0: if (mD3d11Module == NULL || mDxgiModule == NULL) michael@0: { michael@0: ERR("Could not load D3D11 or DXGI library - aborting!\n"); michael@0: return EGL_NOT_INITIALIZED; michael@0: } michael@0: michael@0: // create the D3D11 device michael@0: ASSERT(mDevice == NULL); michael@0: PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); michael@0: michael@0: if (D3D11CreateDevice == NULL) michael@0: { michael@0: ERR("Could not retrieve D3D11CreateDevice address - aborting!\n"); michael@0: return EGL_NOT_INITIALIZED; michael@0: } michael@0: michael@0: D3D_FEATURE_LEVEL featureLevels[] = michael@0: { michael@0: D3D_FEATURE_LEVEL_11_0, michael@0: D3D_FEATURE_LEVEL_10_1, michael@0: D3D_FEATURE_LEVEL_10_0, michael@0: }; michael@0: michael@0: HRESULT result = S_OK; michael@0: michael@0: #ifdef _DEBUG michael@0: result = D3D11CreateDevice(NULL, michael@0: D3D_DRIVER_TYPE_HARDWARE, michael@0: NULL, michael@0: D3D11_CREATE_DEVICE_DEBUG, michael@0: featureLevels, michael@0: ArraySize(featureLevels), michael@0: D3D11_SDK_VERSION, michael@0: &mDevice, michael@0: &mFeatureLevel, michael@0: &mDeviceContext); michael@0: michael@0: if (!mDevice || FAILED(result)) michael@0: { michael@0: ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); michael@0: } michael@0: michael@0: if (!mDevice || FAILED(result)) michael@0: #endif michael@0: { michael@0: result = D3D11CreateDevice(NULL, michael@0: D3D_DRIVER_TYPE_HARDWARE, michael@0: NULL, michael@0: 0, michael@0: featureLevels, michael@0: ArraySize(featureLevels), michael@0: D3D11_SDK_VERSION, michael@0: &mDevice, michael@0: &mFeatureLevel, michael@0: &mDeviceContext); michael@0: michael@0: if (!mDevice || FAILED(result)) michael@0: { michael@0: ERR("Could not create D3D11 device - aborting!\n"); michael@0: return EGL_NOT_INITIALIZED; // Cleanup done by destructor through glDestroyRenderer michael@0: } michael@0: } michael@0: michael@0: IDXGIDevice *dxgiDevice = NULL; michael@0: result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); michael@0: michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Could not query DXGI device - aborting!\n"); michael@0: return EGL_NOT_INITIALIZED; michael@0: } michael@0: michael@0: result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); michael@0: michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Could not retrieve DXGI adapter - aborting!\n"); michael@0: return EGL_NOT_INITIALIZED; michael@0: } michael@0: michael@0: dxgiDevice->Release(); michael@0: michael@0: mDxgiAdapter->GetDesc(&mAdapterDescription); michael@0: memset(mDescription, 0, sizeof(mDescription)); michael@0: wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); michael@0: michael@0: result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); michael@0: michael@0: if (!mDxgiFactory || FAILED(result)) michael@0: { michael@0: ERR("Could not create DXGI factory - aborting!\n"); michael@0: return EGL_NOT_INITIALIZED; michael@0: } michael@0: michael@0: // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log michael@0: #if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) michael@0: ID3D11InfoQueue *infoQueue; michael@0: result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); michael@0: michael@0: if (SUCCEEDED(result)) michael@0: { michael@0: D3D11_MESSAGE_ID hideMessages[] = michael@0: { michael@0: D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETS_HAZARD, michael@0: D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_HAZARD, michael@0: D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET michael@0: }; michael@0: michael@0: D3D11_INFO_QUEUE_FILTER filter = {0}; michael@0: filter.DenyList.NumIDs = ArraySize(hideMessages); michael@0: filter.DenyList.pIDList = hideMessages; michael@0: michael@0: infoQueue->AddStorageFilterEntries(&filter); michael@0: michael@0: infoQueue->Release(); michael@0: } michael@0: #endif michael@0: michael@0: unsigned int maxSupportedSamples = 0; michael@0: unsigned int rtFormatCount = ArraySize(RenderTargetFormats); michael@0: unsigned int dsFormatCount = ArraySize(DepthStencilFormats); michael@0: for (unsigned int i = 0; i < rtFormatCount + dsFormatCount; ++i) michael@0: { michael@0: DXGI_FORMAT format = (i < rtFormatCount) ? RenderTargetFormats[i] : DepthStencilFormats[i - rtFormatCount]; michael@0: if (format != DXGI_FORMAT_UNKNOWN) michael@0: { michael@0: UINT formatSupport; michael@0: result = mDevice->CheckFormatSupport(format, &formatSupport); michael@0: if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET)) michael@0: { michael@0: MultisampleSupportInfo supportInfo; michael@0: michael@0: for (unsigned int j = 1; j <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; j++) michael@0: { michael@0: result = mDevice->CheckMultisampleQualityLevels(format, j, &supportInfo.qualityLevels[j - 1]); michael@0: if (SUCCEEDED(result) && supportInfo.qualityLevels[j - 1] > 0) michael@0: { michael@0: maxSupportedSamples = std::max(j, maxSupportedSamples); michael@0: } michael@0: else michael@0: { michael@0: supportInfo.qualityLevels[j - 1] = 0; michael@0: } michael@0: } michael@0: michael@0: mMultisampleSupportMap.insert(std::make_pair(format, supportInfo)); michael@0: } michael@0: } michael@0: } michael@0: mMaxSupportedSamples = maxSupportedSamples; michael@0: michael@0: initializeDevice(); michael@0: michael@0: // BGRA texture support is optional in feature levels 10 and 10_1 michael@0: UINT formatSupport; michael@0: result = mDevice->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &formatSupport); michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Error checking BGRA format support: 0x%08X", result); michael@0: } michael@0: else michael@0: { michael@0: const int flags = (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET); michael@0: mBGRATextureSupport = (formatSupport & flags) == flags; michael@0: } michael@0: michael@0: // Check floating point texture support michael@0: static const unsigned int requiredTextureFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE; michael@0: static const unsigned int requiredRenderableFlags = D3D11_FORMAT_SUPPORT_RENDER_TARGET; michael@0: static const unsigned int requiredFilterFlags = D3D11_FORMAT_SUPPORT_SHADER_SAMPLE; michael@0: michael@0: DXGI_FORMAT float16Formats[] = michael@0: { michael@0: DXGI_FORMAT_R16_FLOAT, michael@0: DXGI_FORMAT_R16G16_FLOAT, michael@0: DXGI_FORMAT_R16G16B16A16_FLOAT, michael@0: }; michael@0: michael@0: DXGI_FORMAT float32Formats[] = michael@0: { michael@0: DXGI_FORMAT_R32_FLOAT, michael@0: DXGI_FORMAT_R32G32_FLOAT, michael@0: DXGI_FORMAT_R32G32B32_FLOAT, michael@0: DXGI_FORMAT_R32G32B32A32_FLOAT, michael@0: }; michael@0: michael@0: mFloat16TextureSupport = true; michael@0: mFloat16FilterSupport = true; michael@0: mFloat16RenderSupport = true; michael@0: for (unsigned int i = 0; i < ArraySize(float16Formats); i++) michael@0: { michael@0: if (SUCCEEDED(mDevice->CheckFormatSupport(float16Formats[i], &formatSupport))) michael@0: { michael@0: mFloat16TextureSupport = mFloat16TextureSupport && (formatSupport & requiredTextureFlags) == requiredTextureFlags; michael@0: mFloat16FilterSupport = mFloat16FilterSupport && (formatSupport & requiredFilterFlags) == requiredFilterFlags; michael@0: mFloat16RenderSupport = mFloat16RenderSupport && (formatSupport & requiredRenderableFlags) == requiredRenderableFlags; michael@0: } michael@0: else michael@0: { michael@0: mFloat16TextureSupport = false; michael@0: mFloat16RenderSupport = false; michael@0: mFloat16FilterSupport = false; michael@0: } michael@0: } michael@0: michael@0: mFloat32TextureSupport = true; michael@0: mFloat32FilterSupport = true; michael@0: mFloat32RenderSupport = true; michael@0: for (unsigned int i = 0; i < ArraySize(float32Formats); i++) michael@0: { michael@0: if (SUCCEEDED(mDevice->CheckFormatSupport(float32Formats[i], &formatSupport))) michael@0: { michael@0: mFloat32TextureSupport = mFloat32TextureSupport && (formatSupport & requiredTextureFlags) == requiredTextureFlags; michael@0: mFloat32FilterSupport = mFloat32FilterSupport && (formatSupport & requiredFilterFlags) == requiredFilterFlags; michael@0: mFloat32RenderSupport = mFloat32RenderSupport && (formatSupport & requiredRenderableFlags) == requiredRenderableFlags; michael@0: } michael@0: else michael@0: { michael@0: mFloat32TextureSupport = false; michael@0: mFloat32FilterSupport = false; michael@0: mFloat32RenderSupport = false; michael@0: } michael@0: } michael@0: michael@0: // Check compressed texture support michael@0: const unsigned int requiredCompressedTextureFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D; michael@0: michael@0: if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &formatSupport))) michael@0: { michael@0: mDXT1TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags; michael@0: } michael@0: else michael@0: { michael@0: mDXT1TextureSupport = false; michael@0: } michael@0: michael@0: if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &formatSupport))) michael@0: { michael@0: mDXT3TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags; michael@0: } michael@0: else michael@0: { michael@0: mDXT3TextureSupport = false; michael@0: } michael@0: michael@0: if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC5_UNORM, &formatSupport))) michael@0: { michael@0: mDXT5TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags; michael@0: } michael@0: else michael@0: { michael@0: mDXT5TextureSupport = false; michael@0: } michael@0: michael@0: // Check depth texture support michael@0: DXGI_FORMAT depthTextureFormats[] = michael@0: { michael@0: DXGI_FORMAT_D16_UNORM, michael@0: DXGI_FORMAT_D24_UNORM_S8_UINT, michael@0: }; michael@0: michael@0: static const unsigned int requiredDepthTextureFlags = D3D11_FORMAT_SUPPORT_DEPTH_STENCIL | michael@0: D3D11_FORMAT_SUPPORT_TEXTURE2D; michael@0: michael@0: mDepthTextureSupport = true; michael@0: for (unsigned int i = 0; i < ArraySize(depthTextureFormats); i++) michael@0: { michael@0: if (SUCCEEDED(mDevice->CheckFormatSupport(depthTextureFormats[i], &formatSupport))) michael@0: { michael@0: mDepthTextureSupport = mDepthTextureSupport && ((formatSupport & requiredDepthTextureFlags) == requiredDepthTextureFlags); michael@0: } michael@0: else michael@0: { michael@0: mDepthTextureSupport = false; michael@0: } michael@0: } michael@0: michael@0: return EGL_SUCCESS; michael@0: } michael@0: michael@0: // do any one-time device initialization michael@0: // NOTE: this is also needed after a device lost/reset michael@0: // to reset the scene status and ensure the default states are reset. michael@0: void Renderer11::initializeDevice() michael@0: { michael@0: mStateCache.initialize(mDevice); michael@0: mInputLayoutCache.initialize(mDevice, mDeviceContext); michael@0: michael@0: ASSERT(!mVertexDataManager && !mIndexDataManager); michael@0: mVertexDataManager = new VertexDataManager(this); michael@0: mIndexDataManager = new IndexDataManager(this); michael@0: michael@0: markAllStateDirty(); michael@0: } michael@0: michael@0: int Renderer11::generateConfigs(ConfigDesc **configDescList) michael@0: { michael@0: unsigned int numRenderFormats = ArraySize(RenderTargetFormats); michael@0: unsigned int numDepthFormats = ArraySize(DepthStencilFormats); michael@0: (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats]; michael@0: int numConfigs = 0; michael@0: michael@0: for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++) michael@0: { michael@0: for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) michael@0: { michael@0: DXGI_FORMAT renderTargetFormat = RenderTargetFormats[formatIndex]; michael@0: michael@0: UINT formatSupport = 0; michael@0: HRESULT result = mDevice->CheckFormatSupport(renderTargetFormat, &formatSupport); michael@0: michael@0: if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) michael@0: { michael@0: DXGI_FORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex]; michael@0: michael@0: bool depthStencilFormatOK = true; michael@0: michael@0: if (depthStencilFormat != DXGI_FORMAT_UNKNOWN) michael@0: { michael@0: UINT formatSupport = 0; michael@0: result = mDevice->CheckFormatSupport(depthStencilFormat, &formatSupport); michael@0: depthStencilFormatOK = SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL); michael@0: } michael@0: michael@0: if (depthStencilFormatOK) michael@0: { michael@0: ConfigDesc newConfig; michael@0: newConfig.renderTargetFormat = d3d11_gl::ConvertBackBufferFormat(renderTargetFormat); michael@0: newConfig.depthStencilFormat = d3d11_gl::ConvertDepthStencilFormat(depthStencilFormat); michael@0: newConfig.multiSample = 0; // FIXME: enumerate multi-sampling michael@0: newConfig.fastConfig = true; // Assume all DX11 format conversions to be fast michael@0: michael@0: (*configDescList)[numConfigs++] = newConfig; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return numConfigs; michael@0: } michael@0: michael@0: void Renderer11::deleteConfigs(ConfigDesc *configDescList) michael@0: { michael@0: delete [] (configDescList); michael@0: } michael@0: michael@0: void Renderer11::sync(bool block) michael@0: { michael@0: if (block) michael@0: { michael@0: HRESULT result; michael@0: michael@0: if (!mSyncQuery) michael@0: { michael@0: D3D11_QUERY_DESC queryDesc; michael@0: queryDesc.Query = D3D11_QUERY_EVENT; michael@0: queryDesc.MiscFlags = 0; michael@0: michael@0: result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); michael@0: ASSERT(SUCCEEDED(result)); michael@0: } michael@0: michael@0: mDeviceContext->End(mSyncQuery); michael@0: mDeviceContext->Flush(); michael@0: michael@0: do michael@0: { michael@0: result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); michael@0: michael@0: // Keep polling, but allow other threads to do something useful first michael@0: Sleep(0); michael@0: michael@0: if (testDeviceLost(true)) michael@0: { michael@0: return; michael@0: } michael@0: } michael@0: while (result == S_FALSE); michael@0: } michael@0: else michael@0: { michael@0: mDeviceContext->Flush(); michael@0: } michael@0: } michael@0: michael@0: SwapChain *Renderer11::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) michael@0: { michael@0: return new rx::SwapChain11(this, window, shareHandle, backBufferFormat, depthBufferFormat); michael@0: } michael@0: michael@0: void Renderer11::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) michael@0: { michael@0: if (type == gl::SAMPLER_PIXEL) michael@0: { michael@0: if (index < 0 || index >= gl::MAX_TEXTURE_IMAGE_UNITS) michael@0: { michael@0: ERR("Pixel shader sampler index %i is not valid.", index); michael@0: return; michael@0: } michael@0: michael@0: if (mForceSetPixelSamplerStates[index] || memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) michael@0: { michael@0: ID3D11SamplerState *dxSamplerState = mStateCache.getSamplerState(samplerState); michael@0: michael@0: if (!dxSamplerState) michael@0: { michael@0: ERR("NULL sampler state returned by RenderStateCache::getSamplerState, setting the default" michael@0: "sampler state for pixel shaders at slot %i.", index); michael@0: } michael@0: michael@0: mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); michael@0: michael@0: mCurPixelSamplerStates[index] = samplerState; michael@0: } michael@0: michael@0: mForceSetPixelSamplerStates[index] = false; michael@0: } michael@0: else if (type == gl::SAMPLER_VERTEX) michael@0: { michael@0: if (index < 0 || index >= (int)getMaxVertexTextureImageUnits()) michael@0: { michael@0: ERR("Vertex shader sampler index %i is not valid.", index); michael@0: return; michael@0: } michael@0: michael@0: if (mForceSetVertexSamplerStates[index] || memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) michael@0: { michael@0: ID3D11SamplerState *dxSamplerState = mStateCache.getSamplerState(samplerState); michael@0: michael@0: if (!dxSamplerState) michael@0: { michael@0: ERR("NULL sampler state returned by RenderStateCache::getSamplerState, setting the default" michael@0: "sampler state for vertex shaders at slot %i.", index); michael@0: } michael@0: michael@0: mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); michael@0: michael@0: mCurVertexSamplerStates[index] = samplerState; michael@0: } michael@0: michael@0: mForceSetVertexSamplerStates[index] = false; michael@0: } michael@0: else UNREACHABLE(); michael@0: } michael@0: michael@0: void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) michael@0: { michael@0: ID3D11ShaderResourceView *textureSRV = NULL; michael@0: unsigned int serial = 0; michael@0: bool forceSetTexture = false; michael@0: michael@0: if (texture) michael@0: { michael@0: TextureStorageInterface *texStorage = texture->getNativeTexture(); michael@0: if (texStorage) michael@0: { michael@0: TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage->getStorageInstance()); michael@0: textureSRV = storage11->getSRV(); michael@0: } michael@0: michael@0: // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly michael@0: // missing the shader resource view michael@0: ASSERT(textureSRV != NULL); michael@0: michael@0: serial = texture->getTextureSerial(); michael@0: forceSetTexture = texture->hasDirtyImages(); michael@0: } michael@0: michael@0: if (type == gl::SAMPLER_PIXEL) michael@0: { michael@0: if (index < 0 || index >= gl::MAX_TEXTURE_IMAGE_UNITS) michael@0: { michael@0: ERR("Pixel shader sampler index %i is not valid.", index); michael@0: return; michael@0: } michael@0: michael@0: if (forceSetTexture || mCurPixelTextureSerials[index] != serial) michael@0: { michael@0: mDeviceContext->PSSetShaderResources(index, 1, &textureSRV); michael@0: } michael@0: michael@0: mCurPixelTextureSerials[index] = serial; michael@0: } michael@0: else if (type == gl::SAMPLER_VERTEX) michael@0: { michael@0: if (index < 0 || index >= (int)getMaxVertexTextureImageUnits()) michael@0: { michael@0: ERR("Vertex shader sampler index %i is not valid.", index); michael@0: return; michael@0: } michael@0: michael@0: if (forceSetTexture || mCurVertexTextureSerials[index] != serial) michael@0: { michael@0: mDeviceContext->VSSetShaderResources(index, 1, &textureSRV); michael@0: } michael@0: michael@0: mCurVertexTextureSerials[index] = serial; michael@0: } michael@0: else UNREACHABLE(); michael@0: } michael@0: michael@0: void Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) michael@0: { michael@0: if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) michael@0: { michael@0: ID3D11RasterizerState *dxRasterState = mStateCache.getRasterizerState(rasterState, mScissorEnabled, michael@0: mCurDepthSize); michael@0: if (!dxRasterState) michael@0: { michael@0: ERR("NULL rasterizer state returned by RenderStateCache::getRasterizerState, setting the default" michael@0: "rasterizer state."); michael@0: } michael@0: michael@0: mDeviceContext->RSSetState(dxRasterState); michael@0: michael@0: mCurRasterState = rasterState; michael@0: } michael@0: michael@0: mForceSetRasterState = false; michael@0: } michael@0: michael@0: void Renderer11::setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor, michael@0: unsigned int sampleMask) michael@0: { michael@0: if (mForceSetBlendState || michael@0: memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 || michael@0: memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0 || michael@0: sampleMask != mCurSampleMask) michael@0: { michael@0: ID3D11BlendState *dxBlendState = mStateCache.getBlendState(blendState); michael@0: if (!dxBlendState) michael@0: { michael@0: ERR("NULL blend state returned by RenderStateCache::getBlendState, setting the default " michael@0: "blend state."); michael@0: } michael@0: michael@0: float blendColors[4] = {0.0f}; michael@0: if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && michael@0: blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) michael@0: { michael@0: blendColors[0] = blendColor.red; michael@0: blendColors[1] = blendColor.green; michael@0: blendColors[2] = blendColor.blue; michael@0: blendColors[3] = blendColor.alpha; michael@0: } michael@0: else michael@0: { michael@0: blendColors[0] = blendColor.alpha; michael@0: blendColors[1] = blendColor.alpha; michael@0: blendColors[2] = blendColor.alpha; michael@0: blendColors[3] = blendColor.alpha; michael@0: } michael@0: michael@0: mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask); michael@0: michael@0: mCurBlendState = blendState; michael@0: mCurBlendColor = blendColor; michael@0: mCurSampleMask = sampleMask; michael@0: } michael@0: michael@0: mForceSetBlendState = false; michael@0: } michael@0: michael@0: void Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, michael@0: int stencilBackRef, bool frontFaceCCW) michael@0: { michael@0: if (mForceSetDepthStencilState || michael@0: memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 || michael@0: stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef) michael@0: { michael@0: if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || michael@0: stencilRef != stencilBackRef || michael@0: depthStencilState.stencilMask != depthStencilState.stencilBackMask) michael@0: { michael@0: ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are " michael@0: "invalid under WebGL."); michael@0: return gl::error(GL_INVALID_OPERATION); michael@0: } michael@0: michael@0: ID3D11DepthStencilState *dxDepthStencilState = mStateCache.getDepthStencilState(depthStencilState); michael@0: if (!dxDepthStencilState) michael@0: { michael@0: ERR("NULL depth stencil state returned by RenderStateCache::getDepthStencilState, " michael@0: "setting the default depth stencil state."); michael@0: } michael@0: michael@0: mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, static_cast(stencilRef)); michael@0: michael@0: mCurDepthStencilState = depthStencilState; michael@0: mCurStencilRef = stencilRef; michael@0: mCurStencilBackRef = stencilBackRef; michael@0: } michael@0: michael@0: mForceSetDepthStencilState = false; michael@0: } michael@0: michael@0: void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) michael@0: { michael@0: if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || michael@0: enabled != mScissorEnabled) michael@0: { michael@0: if (enabled) michael@0: { michael@0: D3D11_RECT rect; michael@0: rect.left = std::max(0, scissor.x); michael@0: rect.top = std::max(0, scissor.y); michael@0: rect.right = scissor.x + std::max(0, scissor.width); michael@0: rect.bottom = scissor.y + std::max(0, scissor.height); michael@0: michael@0: mDeviceContext->RSSetScissorRects(1, &rect); michael@0: } michael@0: michael@0: if (enabled != mScissorEnabled) michael@0: { michael@0: mForceSetRasterState = true; michael@0: } michael@0: michael@0: mCurScissor = scissor; michael@0: mScissorEnabled = enabled; michael@0: } michael@0: michael@0: mForceSetScissor = false; michael@0: } michael@0: michael@0: bool Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, michael@0: bool ignoreViewport) michael@0: { michael@0: gl::Rectangle actualViewport = viewport; michael@0: float actualZNear = gl::clamp01(zNear); michael@0: float actualZFar = gl::clamp01(zFar); michael@0: if (ignoreViewport) michael@0: { michael@0: actualViewport.x = 0; michael@0: actualViewport.y = 0; michael@0: actualViewport.width = mRenderTargetDesc.width; michael@0: actualViewport.height = mRenderTargetDesc.height; michael@0: actualZNear = 0.0f; michael@0: actualZFar = 1.0f; michael@0: } michael@0: michael@0: // Get D3D viewport bounds, which depends on the feature level michael@0: const Range& viewportBounds = getViewportBounds(); michael@0: michael@0: // Clamp width and height first to the gl maximum, then clamp further if we extend past the D3D maximum bounds michael@0: D3D11_VIEWPORT dxViewport; michael@0: dxViewport.TopLeftX = gl::clamp(actualViewport.x, viewportBounds.start, viewportBounds.end); michael@0: dxViewport.TopLeftY = gl::clamp(actualViewport.y, viewportBounds.start, viewportBounds.end); michael@0: dxViewport.Width = gl::clamp(actualViewport.width, 0, getMaxViewportDimension()); michael@0: dxViewport.Height = gl::clamp(actualViewport.height, 0, getMaxViewportDimension()); michael@0: dxViewport.Width = std::min((int)dxViewport.Width, viewportBounds.end - static_cast(dxViewport.TopLeftX)); michael@0: dxViewport.Height = std::min((int)dxViewport.Height, viewportBounds.end - static_cast(dxViewport.TopLeftY)); michael@0: dxViewport.MinDepth = actualZNear; michael@0: dxViewport.MaxDepth = actualZFar; michael@0: michael@0: if (dxViewport.Width <= 0 || dxViewport.Height <= 0) michael@0: { michael@0: return false; // Nothing to render michael@0: } michael@0: michael@0: bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || michael@0: actualZNear != mCurNear || actualZFar != mCurFar; michael@0: michael@0: if (viewportChanged) michael@0: { michael@0: mDeviceContext->RSSetViewports(1, &dxViewport); michael@0: michael@0: mCurViewport = actualViewport; michael@0: mCurNear = actualZNear; michael@0: mCurFar = actualZFar; michael@0: michael@0: mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f; michael@0: mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f; michael@0: mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); michael@0: mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); michael@0: michael@0: mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; michael@0: mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; michael@0: michael@0: mVertexConstants.depthRange[0] = actualZNear; michael@0: mVertexConstants.depthRange[1] = actualZFar; michael@0: mVertexConstants.depthRange[2] = actualZFar - actualZNear; michael@0: michael@0: mPixelConstants.depthRange[0] = actualZNear; michael@0: mPixelConstants.depthRange[1] = actualZFar; michael@0: mPixelConstants.depthRange[2] = actualZFar - actualZNear; michael@0: } michael@0: michael@0: mForceSetViewport = false; michael@0: return true; michael@0: } michael@0: michael@0: bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) michael@0: { michael@0: D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; michael@0: michael@0: GLsizei minCount = 0; michael@0: michael@0: switch (mode) michael@0: { michael@0: case GL_POINTS: primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; minCount = 1; break; michael@0: case GL_LINES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; minCount = 2; break; michael@0: case GL_LINE_LOOP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; michael@0: case GL_LINE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; michael@0: case GL_TRIANGLES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; michael@0: case GL_TRIANGLE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; minCount = 3; break; michael@0: // emulate fans via rewriting index buffer michael@0: case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; michael@0: default: michael@0: return gl::error(GL_INVALID_ENUM, false); michael@0: } michael@0: michael@0: if (primitiveTopology != mCurrentPrimitiveTopology) michael@0: { michael@0: mDeviceContext->IASetPrimitiveTopology(primitiveTopology); michael@0: mCurrentPrimitiveTopology = primitiveTopology; michael@0: } michael@0: michael@0: return count >= minCount; michael@0: } michael@0: michael@0: bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) michael@0: { michael@0: // Get the color render buffer and serial michael@0: // Also extract the render target dimensions and view michael@0: unsigned int renderTargetWidth = 0; michael@0: unsigned int renderTargetHeight = 0; michael@0: GLenum renderTargetFormat = 0; michael@0: unsigned int renderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {0}; michael@0: ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; michael@0: bool missingColorRenderTarget = true; michael@0: michael@0: for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) michael@0: { michael@0: const GLenum drawBufferState = framebuffer->getDrawBufferState(colorAttachment); michael@0: michael@0: if (framebuffer->getColorbufferType(colorAttachment) != GL_NONE && drawBufferState != GL_NONE) michael@0: { michael@0: // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order) michael@0: ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment)); michael@0: michael@0: gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(colorAttachment); michael@0: michael@0: if (!colorbuffer) michael@0: { michael@0: ERR("render target pointer unexpectedly null."); michael@0: return false; michael@0: } michael@0: michael@0: // check for zero-sized default framebuffer, which is a special case. michael@0: // in this case we do not wish to modify any state and just silently return false. michael@0: // this will not report any gl error but will cause the calling method to return. michael@0: if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: renderTargetSerials[colorAttachment] = colorbuffer->getSerial(); michael@0: michael@0: // Extract the render target dimensions and view michael@0: RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); michael@0: if (!renderTarget) michael@0: { michael@0: ERR("render target pointer unexpectedly null."); michael@0: return false; michael@0: } michael@0: michael@0: framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); michael@0: if (!framebufferRTVs[colorAttachment]) michael@0: { michael@0: ERR("render target view pointer unexpectedly null."); michael@0: return false; michael@0: } michael@0: michael@0: if (missingColorRenderTarget) michael@0: { michael@0: renderTargetWidth = colorbuffer->getWidth(); michael@0: renderTargetHeight = colorbuffer->getHeight(); michael@0: renderTargetFormat = colorbuffer->getActualFormat(); michael@0: missingColorRenderTarget = false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Get the depth stencil render buffer and serials michael@0: gl::Renderbuffer *depthStencil = NULL; michael@0: unsigned int depthbufferSerial = 0; michael@0: unsigned int stencilbufferSerial = 0; michael@0: if (framebuffer->getDepthbufferType() != GL_NONE) michael@0: { michael@0: depthStencil = framebuffer->getDepthbuffer(); michael@0: if (!depthStencil) michael@0: { michael@0: ERR("Depth stencil pointer unexpectedly null."); michael@0: SafeRelease(framebufferRTVs); michael@0: return false; michael@0: } michael@0: michael@0: depthbufferSerial = depthStencil->getSerial(); michael@0: } michael@0: else if (framebuffer->getStencilbufferType() != GL_NONE) michael@0: { michael@0: depthStencil = framebuffer->getStencilbuffer(); michael@0: if (!depthStencil) michael@0: { michael@0: ERR("Depth stencil pointer unexpectedly null."); michael@0: SafeRelease(framebufferRTVs); michael@0: return false; michael@0: } michael@0: michael@0: stencilbufferSerial = depthStencil->getSerial(); michael@0: } michael@0: michael@0: // Extract the depth stencil sizes and view michael@0: unsigned int depthSize = 0; michael@0: unsigned int stencilSize = 0; michael@0: ID3D11DepthStencilView* framebufferDSV = NULL; michael@0: if (depthStencil) michael@0: { michael@0: RenderTarget11 *depthStencilRenderTarget = RenderTarget11::makeRenderTarget11(depthStencil->getDepthStencil()); michael@0: if (!depthStencilRenderTarget) michael@0: { michael@0: ERR("render target pointer unexpectedly null."); michael@0: SafeRelease(framebufferRTVs); michael@0: return false; michael@0: } michael@0: michael@0: framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); michael@0: if (!framebufferDSV) michael@0: { michael@0: ERR("depth stencil view pointer unexpectedly null."); michael@0: SafeRelease(framebufferRTVs); michael@0: return false; michael@0: } michael@0: michael@0: // If there is no render buffer, the width, height and format values come from michael@0: // the depth stencil michael@0: if (missingColorRenderTarget) michael@0: { michael@0: renderTargetWidth = depthStencil->getWidth(); michael@0: renderTargetHeight = depthStencil->getHeight(); michael@0: renderTargetFormat = depthStencil->getActualFormat(); michael@0: } michael@0: michael@0: depthSize = depthStencil->getDepthSize(); michael@0: stencilSize = depthStencil->getStencilSize(); michael@0: } michael@0: michael@0: // Apply the render target and depth stencil michael@0: if (!mRenderTargetDescInitialized || !mDepthStencilInitialized || michael@0: memcmp(renderTargetSerials, mAppliedRenderTargetSerials, sizeof(renderTargetSerials)) != 0 || michael@0: depthbufferSerial != mAppliedDepthbufferSerial || michael@0: stencilbufferSerial != mAppliedStencilbufferSerial) michael@0: { michael@0: mDeviceContext->OMSetRenderTargets(getMaxRenderTargets(), framebufferRTVs, framebufferDSV); michael@0: michael@0: mRenderTargetDesc.width = renderTargetWidth; michael@0: mRenderTargetDesc.height = renderTargetHeight; michael@0: mRenderTargetDesc.format = renderTargetFormat; michael@0: mForceSetViewport = true; michael@0: mForceSetScissor = true; michael@0: michael@0: if (!mDepthStencilInitialized || depthSize != mCurDepthSize) michael@0: { michael@0: mCurDepthSize = depthSize; michael@0: mForceSetRasterState = true; michael@0: } michael@0: michael@0: mCurStencilSize = stencilSize; michael@0: michael@0: for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) michael@0: { michael@0: mAppliedRenderTargetSerials[rtIndex] = renderTargetSerials[rtIndex]; michael@0: } michael@0: mAppliedDepthbufferSerial = depthbufferSerial; michael@0: mAppliedStencilbufferSerial = stencilbufferSerial; michael@0: mRenderTargetDescInitialized = true; michael@0: mDepthStencilInitialized = true; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: GLenum Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances) michael@0: { michael@0: TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; michael@0: GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances); michael@0: if (err != GL_NO_ERROR) michael@0: { michael@0: return err; michael@0: } michael@0: michael@0: return mInputLayoutCache.applyVertexBuffers(attributes, programBinary); michael@0: } michael@0: michael@0: GLenum Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) michael@0: { michael@0: GLenum err = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); michael@0: michael@0: if (err == GL_NO_ERROR) michael@0: { michael@0: if (indexInfo->storage) michael@0: { michael@0: if (indexInfo->serial != mAppliedStorageIBSerial || indexInfo->startOffset != mAppliedIBOffset) michael@0: { michael@0: BufferStorage11 *storage = BufferStorage11::makeBufferStorage11(indexInfo->storage); michael@0: IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); michael@0: michael@0: mDeviceContext->IASetIndexBuffer(storage->getBuffer(), indexBuffer->getIndexFormat(), indexInfo->startOffset); michael@0: michael@0: mAppliedIBSerial = 0; michael@0: mAppliedStorageIBSerial = storage->getSerial(); michael@0: mAppliedIBOffset = indexInfo->startOffset; michael@0: } michael@0: } michael@0: else if (indexInfo->serial != mAppliedIBSerial || indexInfo->startOffset != mAppliedIBOffset) michael@0: { michael@0: IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); michael@0: michael@0: mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexInfo->startOffset); michael@0: michael@0: mAppliedIBSerial = indexInfo->serial; michael@0: mAppliedStorageIBSerial = 0; michael@0: mAppliedIBOffset = indexInfo->startOffset; michael@0: } michael@0: } michael@0: michael@0: return err; michael@0: } michael@0: michael@0: void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances) michael@0: { michael@0: if (mode == GL_LINE_LOOP) michael@0: { michael@0: drawLineLoop(count, GL_NONE, NULL, 0, NULL); michael@0: } michael@0: else if (mode == GL_TRIANGLE_FAN) michael@0: { michael@0: drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances); michael@0: } michael@0: else if (instances > 0) michael@0: { michael@0: mDeviceContext->DrawInstanced(count, instances, 0, 0); michael@0: } michael@0: else michael@0: { michael@0: mDeviceContext->Draw(count, 0); michael@0: } michael@0: } michael@0: michael@0: void Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) michael@0: { michael@0: if (mode == GL_LINE_LOOP) michael@0: { michael@0: drawLineLoop(count, type, indices, indexInfo.minIndex, elementArrayBuffer); michael@0: } michael@0: else if (mode == GL_TRIANGLE_FAN) michael@0: { michael@0: drawTriangleFan(count, type, indices, indexInfo.minIndex, elementArrayBuffer, instances); michael@0: } michael@0: else if (instances > 0) michael@0: { michael@0: mDeviceContext->DrawIndexedInstanced(count, instances, 0, -static_cast(indexInfo.minIndex), 0); michael@0: } michael@0: else michael@0: { michael@0: mDeviceContext->DrawIndexed(count, 0, -static_cast(indexInfo.minIndex)); michael@0: } michael@0: } michael@0: michael@0: void Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) michael@0: { michael@0: // Get the raw indices for an indexed draw michael@0: if (type != GL_NONE && elementArrayBuffer) michael@0: { michael@0: gl::Buffer *indexBuffer = elementArrayBuffer; michael@0: BufferStorage *storage = indexBuffer->getStorage(); michael@0: intptr_t offset = reinterpret_cast(indices); michael@0: indices = static_cast(storage->getData()) + offset; michael@0: } michael@0: michael@0: if (!mLineLoopIB) michael@0: { michael@0: mLineLoopIB = new StreamingIndexBufferInterface(this); michael@0: if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT)) michael@0: { michael@0: delete mLineLoopIB; michael@0: mLineLoopIB = NULL; michael@0: michael@0: ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: } michael@0: michael@0: // Checked by Renderer11::applyPrimitiveType michael@0: ASSERT(count >= 0); michael@0: michael@0: if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) michael@0: { michael@0: ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned int); michael@0: if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)) michael@0: { michael@0: ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: void* mappedMemory = NULL; michael@0: unsigned int offset; michael@0: if (!mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) michael@0: { michael@0: ERR("Could not map index buffer for GL_LINE_LOOP."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: unsigned int *data = reinterpret_cast(mappedMemory); michael@0: unsigned int indexBufferOffset = offset; michael@0: michael@0: switch (type) michael@0: { michael@0: case GL_NONE: // Non-indexed draw michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: data[i] = i; michael@0: } michael@0: data[count] = 0; michael@0: break; michael@0: case GL_UNSIGNED_BYTE: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: data[i] = static_cast(indices)[i]; michael@0: } michael@0: data[count] = static_cast(indices)[0]; michael@0: break; michael@0: case GL_UNSIGNED_SHORT: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: data[i] = static_cast(indices)[i]; michael@0: } michael@0: data[count] = static_cast(indices)[0]; michael@0: break; michael@0: case GL_UNSIGNED_INT: michael@0: for (int i = 0; i < count; i++) michael@0: { michael@0: data[i] = static_cast(indices)[i]; michael@0: } michael@0: data[count] = static_cast(indices)[0]; michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: michael@0: if (!mLineLoopIB->unmapBuffer()) michael@0: { michael@0: ERR("Could not unmap index buffer for GL_LINE_LOOP."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: if (mAppliedIBSerial != mLineLoopIB->getSerial() || mAppliedIBOffset != indexBufferOffset) michael@0: { michael@0: IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); michael@0: michael@0: mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset); michael@0: mAppliedIBSerial = mLineLoopIB->getSerial(); michael@0: mAppliedStorageIBSerial = 0; michael@0: mAppliedIBOffset = indexBufferOffset; michael@0: } michael@0: michael@0: mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); michael@0: } michael@0: michael@0: void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances) michael@0: { michael@0: // Get the raw indices for an indexed draw michael@0: if (type != GL_NONE && elementArrayBuffer) michael@0: { michael@0: gl::Buffer *indexBuffer = elementArrayBuffer; michael@0: BufferStorage *storage = indexBuffer->getStorage(); michael@0: intptr_t offset = reinterpret_cast(indices); michael@0: indices = static_cast(storage->getData()) + offset; michael@0: } michael@0: michael@0: if (!mTriangleFanIB) michael@0: { michael@0: mTriangleFanIB = new StreamingIndexBufferInterface(this); michael@0: if (!mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT)) michael@0: { michael@0: delete mTriangleFanIB; michael@0: mTriangleFanIB = NULL; michael@0: michael@0: ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: } michael@0: michael@0: // Checked by Renderer11::applyPrimitiveType michael@0: ASSERT(count >= 3); michael@0: michael@0: const unsigned int numTris = count - 2; michael@0: michael@0: if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) michael@0: { michael@0: ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int); michael@0: if (!mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT)) michael@0: { michael@0: ERR("Could not reserve enough space in scratch index buffer for GL_TRIANGLE_FAN."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: void* mappedMemory = NULL; michael@0: unsigned int offset; michael@0: if (!mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset)) michael@0: { michael@0: ERR("Could not map scratch index buffer for GL_TRIANGLE_FAN."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: unsigned int *data = reinterpret_cast(mappedMemory); michael@0: unsigned int indexBufferOffset = offset; michael@0: michael@0: switch (type) michael@0: { michael@0: case GL_NONE: // Non-indexed draw michael@0: for (unsigned int i = 0; i < numTris; i++) michael@0: { michael@0: data[i*3 + 0] = 0; michael@0: data[i*3 + 1] = i + 1; michael@0: data[i*3 + 2] = i + 2; michael@0: } michael@0: break; michael@0: case GL_UNSIGNED_BYTE: michael@0: for (unsigned int i = 0; i < numTris; i++) michael@0: { michael@0: data[i*3 + 0] = static_cast(indices)[0]; michael@0: data[i*3 + 1] = static_cast(indices)[i + 1]; michael@0: data[i*3 + 2] = static_cast(indices)[i + 2]; michael@0: } michael@0: break; michael@0: case GL_UNSIGNED_SHORT: michael@0: for (unsigned int i = 0; i < numTris; i++) michael@0: { michael@0: data[i*3 + 0] = static_cast(indices)[0]; michael@0: data[i*3 + 1] = static_cast(indices)[i + 1]; michael@0: data[i*3 + 2] = static_cast(indices)[i + 2]; michael@0: } michael@0: break; michael@0: case GL_UNSIGNED_INT: michael@0: for (unsigned int i = 0; i < numTris; i++) michael@0: { michael@0: data[i*3 + 0] = static_cast(indices)[0]; michael@0: data[i*3 + 1] = static_cast(indices)[i + 1]; michael@0: data[i*3 + 2] = static_cast(indices)[i + 2]; michael@0: } michael@0: break; michael@0: default: UNREACHABLE(); michael@0: } michael@0: michael@0: if (!mTriangleFanIB->unmapBuffer()) michael@0: { michael@0: ERR("Could not unmap scratch index buffer for GL_TRIANGLE_FAN."); michael@0: return gl::error(GL_OUT_OF_MEMORY); michael@0: } michael@0: michael@0: if (mAppliedIBSerial != mTriangleFanIB->getSerial() || mAppliedIBOffset != indexBufferOffset) michael@0: { michael@0: IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); michael@0: michael@0: mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset); michael@0: mAppliedIBSerial = mTriangleFanIB->getSerial(); michael@0: mAppliedStorageIBSerial = 0; michael@0: mAppliedIBOffset = indexBufferOffset; michael@0: } michael@0: michael@0: if (instances > 0) michael@0: { michael@0: mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0); michael@0: } michael@0: else michael@0: { michael@0: mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex); michael@0: } michael@0: } michael@0: michael@0: void Renderer11::applyShaders(gl::ProgramBinary *programBinary) michael@0: { michael@0: unsigned int programBinarySerial = programBinary->getSerial(); michael@0: const bool updateProgramState = (programBinarySerial != mAppliedProgramBinarySerial); michael@0: michael@0: if (updateProgramState) michael@0: { michael@0: ShaderExecutable *vertexExe = programBinary->getVertexExecutable(); michael@0: ShaderExecutable *pixelExe = programBinary->getPixelExecutable(); michael@0: michael@0: ID3D11VertexShader *vertexShader = NULL; michael@0: if (vertexExe) vertexShader = ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader(); michael@0: michael@0: ID3D11PixelShader *pixelShader = NULL; michael@0: if (pixelExe) pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader(); michael@0: michael@0: mDeviceContext->PSSetShader(pixelShader, NULL, 0); michael@0: mDeviceContext->VSSetShader(vertexShader, NULL, 0); michael@0: michael@0: programBinary->dirtyAllUniforms(); michael@0: michael@0: mAppliedProgramBinarySerial = programBinarySerial; michael@0: } michael@0: michael@0: // Only use the geometry shader currently for point sprite drawing michael@0: const bool usesGeometryShader = (programBinary->usesGeometryShader() && mCurRasterState.pointDrawMode); michael@0: michael@0: if (updateProgramState || usesGeometryShader != mIsGeometryShaderActive) michael@0: { michael@0: if (usesGeometryShader) michael@0: { michael@0: ShaderExecutable *geometryExe = programBinary->getGeometryExecutable(); michael@0: ID3D11GeometryShader *geometryShader = ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader(); michael@0: mDeviceContext->GSSetShader(geometryShader, NULL, 0); michael@0: } michael@0: else michael@0: { michael@0: mDeviceContext->GSSetShader(NULL, NULL, 0); michael@0: } michael@0: michael@0: mIsGeometryShaderActive = usesGeometryShader; michael@0: } michael@0: } michael@0: michael@0: void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray) michael@0: { michael@0: ShaderExecutable11 *vertexExecutable = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable()); michael@0: ShaderExecutable11 *pixelExecutable = ShaderExecutable11::makeShaderExecutable11(programBinary->getPixelExecutable()); michael@0: michael@0: unsigned int totalRegisterCountVS = 0; michael@0: unsigned int totalRegisterCountPS = 0; michael@0: michael@0: bool vertexUniformsDirty = false; michael@0: bool pixelUniformsDirty = false; michael@0: michael@0: for (gl::UniformArray::const_iterator uniform_iterator = uniformArray->begin(); uniform_iterator != uniformArray->end(); uniform_iterator++) michael@0: { michael@0: const gl::Uniform *uniform = *uniform_iterator; michael@0: michael@0: if (uniform->vsRegisterIndex >= 0) michael@0: { michael@0: totalRegisterCountVS += uniform->registerCount; michael@0: vertexUniformsDirty = vertexUniformsDirty || uniform->dirty; michael@0: } michael@0: michael@0: if (uniform->psRegisterIndex >= 0) michael@0: { michael@0: totalRegisterCountPS += uniform->registerCount; michael@0: pixelUniformsDirty = pixelUniformsDirty || uniform->dirty; michael@0: } michael@0: } michael@0: michael@0: ID3D11Buffer *vertexConstantBuffer = vertexExecutable->getConstantBuffer(mDevice, totalRegisterCountVS); michael@0: ID3D11Buffer *pixelConstantBuffer = pixelExecutable->getConstantBuffer(mDevice, totalRegisterCountPS); michael@0: michael@0: float (*mapVS)[4] = NULL; michael@0: float (*mapPS)[4] = NULL; michael@0: michael@0: if (totalRegisterCountVS > 0 && vertexUniformsDirty) michael@0: { michael@0: D3D11_MAPPED_SUBRESOURCE map = {0}; michael@0: HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); michael@0: ASSERT(SUCCEEDED(result)); michael@0: mapVS = (float(*)[4])map.pData; michael@0: } michael@0: michael@0: if (totalRegisterCountPS > 0 && pixelUniformsDirty) michael@0: { michael@0: D3D11_MAPPED_SUBRESOURCE map = {0}; michael@0: HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); michael@0: ASSERT(SUCCEEDED(result)); michael@0: mapPS = (float(*)[4])map.pData; michael@0: } michael@0: michael@0: for (gl::UniformArray::iterator uniform_iterator = uniformArray->begin(); uniform_iterator != uniformArray->end(); uniform_iterator++) michael@0: { michael@0: gl::Uniform *uniform = *uniform_iterator; michael@0: michael@0: if (uniform->type != GL_SAMPLER_2D && uniform->type != GL_SAMPLER_CUBE) michael@0: { michael@0: if (uniform->vsRegisterIndex >= 0 && mapVS) michael@0: { michael@0: memcpy(mapVS + uniform->vsRegisterIndex, uniform->data, uniform->registerCount * sizeof(float[4])); michael@0: } michael@0: michael@0: if (uniform->psRegisterIndex >= 0 && mapPS) michael@0: { michael@0: memcpy(mapPS + uniform->psRegisterIndex, uniform->data, uniform->registerCount * sizeof(float[4])); michael@0: } michael@0: } michael@0: michael@0: uniform->dirty = false; michael@0: } michael@0: michael@0: if (mapVS) michael@0: { michael@0: mDeviceContext->Unmap(vertexConstantBuffer, 0); michael@0: } michael@0: michael@0: if (mapPS) michael@0: { michael@0: mDeviceContext->Unmap(pixelConstantBuffer, 0); michael@0: } michael@0: michael@0: if (mCurrentVertexConstantBuffer != vertexConstantBuffer) michael@0: { michael@0: mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); michael@0: mCurrentVertexConstantBuffer = vertexConstantBuffer; michael@0: } michael@0: michael@0: if (mCurrentPixelConstantBuffer != pixelConstantBuffer) michael@0: { michael@0: mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); michael@0: mCurrentPixelConstantBuffer = pixelConstantBuffer; michael@0: } michael@0: michael@0: // Driver uniforms michael@0: if (!mDriverConstantBufferVS) michael@0: { michael@0: D3D11_BUFFER_DESC constantBufferDescription = {0}; michael@0: constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants); michael@0: constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; michael@0: constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; michael@0: constantBufferDescription.CPUAccessFlags = 0; michael@0: constantBufferDescription.MiscFlags = 0; michael@0: constantBufferDescription.StructureByteStride = 0; michael@0: michael@0: HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: michael@0: mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); michael@0: } michael@0: michael@0: if (!mDriverConstantBufferPS) michael@0: { michael@0: D3D11_BUFFER_DESC constantBufferDescription = {0}; michael@0: constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants); michael@0: constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; michael@0: constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; michael@0: constantBufferDescription.CPUAccessFlags = 0; michael@0: constantBufferDescription.MiscFlags = 0; michael@0: constantBufferDescription.StructureByteStride = 0; michael@0: michael@0: HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: michael@0: mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); michael@0: } michael@0: michael@0: if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0) michael@0: { michael@0: mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0); michael@0: memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants)); michael@0: } michael@0: michael@0: if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0) michael@0: { michael@0: mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0); michael@0: memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants)); michael@0: } michael@0: michael@0: // needed for the point sprite geometry shader michael@0: if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) michael@0: { michael@0: mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); michael@0: mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; michael@0: } michael@0: } michael@0: michael@0: void Renderer11::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) michael@0: { michael@0: bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha; michael@0: bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) && michael@0: !(clearParams.colorMaskRed && clearParams.colorMaskGreen && michael@0: clearParams.colorMaskBlue && alphaUnmasked); michael@0: michael@0: unsigned int stencilUnmasked = 0x0; michael@0: if (frameBuffer->hasStencil()) michael@0: { michael@0: unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat()); michael@0: stencilUnmasked = (0x1 << stencilSize) - 1; michael@0: } michael@0: bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) && michael@0: (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; michael@0: michael@0: bool needScissoredClear = mScissorEnabled && (mCurScissor.x > 0 || mCurScissor.y > 0 || michael@0: mCurScissor.x + mCurScissor.width < mRenderTargetDesc.width || michael@0: mCurScissor.y + mCurScissor.height < mRenderTargetDesc.height); michael@0: michael@0: if (needMaskedColorClear || needMaskedStencilClear || needScissoredClear) michael@0: { michael@0: maskedClear(clearParams, frameBuffer->usingExtendedDrawBuffers()); michael@0: } michael@0: else michael@0: { michael@0: if (clearParams.mask & GL_COLOR_BUFFER_BIT) michael@0: { michael@0: for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) michael@0: { michael@0: if (frameBuffer->isEnabledColorAttachment(colorAttachment)) michael@0: { michael@0: gl::Renderbuffer *renderbufferObject = frameBuffer->getColorbuffer(colorAttachment); michael@0: if (renderbufferObject) michael@0: { michael@0: RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbufferObject->getRenderTarget()); michael@0: if (!renderTarget) michael@0: { michael@0: ERR("render target pointer unexpectedly null."); michael@0: return; michael@0: } michael@0: michael@0: ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); michael@0: if (!framebufferRTV) michael@0: { michael@0: ERR("render target view pointer unexpectedly null."); michael@0: return; michael@0: } michael@0: michael@0: const float clearValues[4] = { clearParams.colorClearValue.red, michael@0: clearParams.colorClearValue.green, michael@0: clearParams.colorClearValue.blue, michael@0: clearParams.colorClearValue.alpha }; michael@0: mDeviceContext->ClearRenderTargetView(framebufferRTV, clearValues); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: if (clearParams.mask & GL_DEPTH_BUFFER_BIT || clearParams.mask & GL_STENCIL_BUFFER_BIT) michael@0: { michael@0: gl::Renderbuffer *renderbufferObject = frameBuffer->getDepthOrStencilbuffer(); michael@0: if (renderbufferObject) michael@0: { michael@0: RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbufferObject->getDepthStencil()); michael@0: if (!renderTarget) michael@0: { michael@0: ERR("render target pointer unexpectedly null."); michael@0: return; michael@0: } michael@0: michael@0: ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); michael@0: if (!framebufferDSV) michael@0: { michael@0: ERR("depth stencil view pointer unexpectedly null."); michael@0: return; michael@0: } michael@0: michael@0: UINT clearFlags = 0; michael@0: if (clearParams.mask & GL_DEPTH_BUFFER_BIT) michael@0: { michael@0: clearFlags |= D3D11_CLEAR_DEPTH; michael@0: } michael@0: if (clearParams.mask & GL_STENCIL_BUFFER_BIT) michael@0: { michael@0: clearFlags |= D3D11_CLEAR_STENCIL; michael@0: } michael@0: michael@0: float depthClear = gl::clamp01(clearParams.depthClearValue); michael@0: UINT8 stencilClear = clearParams.stencilClearValue & 0x000000FF; michael@0: michael@0: mDeviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void Renderer11::maskedClear(const gl::ClearParameters &clearParams, bool usingExtendedDrawBuffers) michael@0: { michael@0: HRESULT result; michael@0: michael@0: if (!mClearResourcesInitialized) michael@0: { michael@0: ASSERT(!mClearVB && !mClearVS && !mClearSinglePS && !mClearMultiplePS && !mClearScissorRS && !mClearNoScissorRS); michael@0: michael@0: D3D11_BUFFER_DESC vbDesc; michael@0: vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4; michael@0: vbDesc.Usage = D3D11_USAGE_DYNAMIC; michael@0: vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; michael@0: vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; michael@0: vbDesc.MiscFlags = 0; michael@0: vbDesc.StructureByteStride = 0; michael@0: michael@0: result = mDevice->CreateBuffer(&vbDesc, NULL, &mClearVB); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearVB, "Renderer11 masked clear vertex buffer"); michael@0: michael@0: D3D11_INPUT_ELEMENT_DESC quadLayout[] = michael@0: { michael@0: { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, michael@0: { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, michael@0: }; michael@0: michael@0: result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Clear, sizeof(g_VS_Clear), &mClearIL); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearIL, "Renderer11 masked clear input layout"); michael@0: michael@0: result = mDevice->CreateVertexShader(g_VS_Clear, sizeof(g_VS_Clear), NULL, &mClearVS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearVS, "Renderer11 masked clear vertex shader"); michael@0: michael@0: result = mDevice->CreatePixelShader(g_PS_ClearSingle, sizeof(g_PS_ClearSingle), NULL, &mClearSinglePS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearSinglePS, "Renderer11 masked clear pixel shader (1 RT)"); michael@0: michael@0: result = mDevice->CreatePixelShader(g_PS_ClearMultiple, sizeof(g_PS_ClearMultiple), NULL, &mClearMultiplePS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearMultiplePS, "Renderer11 masked clear pixel shader (MRT)"); michael@0: michael@0: D3D11_RASTERIZER_DESC rsScissorDesc; michael@0: rsScissorDesc.FillMode = D3D11_FILL_SOLID; michael@0: rsScissorDesc.CullMode = D3D11_CULL_NONE; michael@0: rsScissorDesc.FrontCounterClockwise = FALSE; michael@0: rsScissorDesc.DepthBias = 0; michael@0: rsScissorDesc.DepthBiasClamp = 0.0f; michael@0: rsScissorDesc.SlopeScaledDepthBias = 0.0f; michael@0: rsScissorDesc.DepthClipEnable = FALSE; michael@0: rsScissorDesc.ScissorEnable = TRUE; michael@0: rsScissorDesc.MultisampleEnable = FALSE; michael@0: rsScissorDesc.AntialiasedLineEnable = FALSE; michael@0: michael@0: result = mDevice->CreateRasterizerState(&rsScissorDesc, &mClearScissorRS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearScissorRS, "Renderer11 masked clear scissor rasterizer state"); michael@0: michael@0: D3D11_RASTERIZER_DESC rsNoScissorDesc; michael@0: rsNoScissorDesc.FillMode = D3D11_FILL_SOLID; michael@0: rsNoScissorDesc.CullMode = D3D11_CULL_NONE; michael@0: rsNoScissorDesc.FrontCounterClockwise = FALSE; michael@0: rsNoScissorDesc.DepthBias = 0; michael@0: rsNoScissorDesc.DepthBiasClamp = 0.0f; michael@0: rsNoScissorDesc.SlopeScaledDepthBias = 0.0f; michael@0: rsNoScissorDesc.DepthClipEnable = FALSE; michael@0: rsNoScissorDesc.ScissorEnable = FALSE; michael@0: rsNoScissorDesc.MultisampleEnable = FALSE; michael@0: rsNoScissorDesc.AntialiasedLineEnable = FALSE; michael@0: michael@0: result = mDevice->CreateRasterizerState(&rsNoScissorDesc, &mClearNoScissorRS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mClearNoScissorRS, "Renderer11 masked clear no scissor rasterizer state"); michael@0: michael@0: mClearResourcesInitialized = true; michael@0: } michael@0: michael@0: // Prepare the depth stencil state to write depth values if the depth should be cleared michael@0: // and stencil values if the stencil should be cleared michael@0: gl::DepthStencilState glDSState; michael@0: glDSState.depthTest = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0; michael@0: glDSState.depthFunc = GL_ALWAYS; michael@0: glDSState.depthMask = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0; michael@0: glDSState.stencilTest = (clearParams.mask & GL_STENCIL_BUFFER_BIT) != 0; michael@0: glDSState.stencilFunc = GL_ALWAYS; michael@0: glDSState.stencilMask = 0; michael@0: glDSState.stencilFail = GL_REPLACE; michael@0: glDSState.stencilPassDepthFail = GL_REPLACE; michael@0: glDSState.stencilPassDepthPass = GL_REPLACE; michael@0: glDSState.stencilWritemask = clearParams.stencilWriteMask; michael@0: glDSState.stencilBackFunc = GL_ALWAYS; michael@0: glDSState.stencilBackMask = 0; michael@0: glDSState.stencilBackFail = GL_REPLACE; michael@0: glDSState.stencilBackPassDepthFail = GL_REPLACE; michael@0: glDSState.stencilBackPassDepthPass = GL_REPLACE; michael@0: glDSState.stencilBackWritemask = clearParams.stencilWriteMask; michael@0: michael@0: int stencilClear = clearParams.stencilClearValue & 0x000000FF; michael@0: michael@0: ID3D11DepthStencilState *dsState = mStateCache.getDepthStencilState(glDSState); michael@0: michael@0: // Prepare the blend state to use a write mask if the color buffer should be cleared michael@0: gl::BlendState glBlendState; michael@0: glBlendState.blend = false; michael@0: glBlendState.sourceBlendRGB = GL_ONE; michael@0: glBlendState.destBlendRGB = GL_ZERO; michael@0: glBlendState.sourceBlendAlpha = GL_ONE; michael@0: glBlendState.destBlendAlpha = GL_ZERO; michael@0: glBlendState.blendEquationRGB = GL_FUNC_ADD; michael@0: glBlendState.blendEquationAlpha = GL_FUNC_ADD; michael@0: glBlendState.colorMaskRed = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskRed : false; michael@0: glBlendState.colorMaskGreen = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskGreen : false; michael@0: glBlendState.colorMaskBlue = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskBlue : false; michael@0: glBlendState.colorMaskAlpha = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskAlpha : false; michael@0: glBlendState.sampleAlphaToCoverage = false; michael@0: glBlendState.dither = false; michael@0: michael@0: static const float blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; michael@0: static const UINT sampleMask = 0xFFFFFFFF; michael@0: michael@0: ID3D11BlendState *blendState = mStateCache.getBlendState(glBlendState); michael@0: michael@0: // Set the vertices michael@0: D3D11_MAPPED_SUBRESOURCE mappedResource; michael@0: result = mDeviceContext->Map(mClearVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result); michael@0: return; michael@0: } michael@0: michael@0: d3d11::PositionDepthColorVertex *vertices = reinterpret_cast(mappedResource.pData); michael@0: michael@0: float depthClear = gl::clamp01(clearParams.depthClearValue); michael@0: d3d11::SetPositionDepthColorVertex(&vertices[0], -1.0f, 1.0f, depthClear, clearParams.colorClearValue); michael@0: d3d11::SetPositionDepthColorVertex(&vertices[1], -1.0f, -1.0f, depthClear, clearParams.colorClearValue); michael@0: d3d11::SetPositionDepthColorVertex(&vertices[2], 1.0f, 1.0f, depthClear, clearParams.colorClearValue); michael@0: d3d11::SetPositionDepthColorVertex(&vertices[3], 1.0f, -1.0f, depthClear, clearParams.colorClearValue); michael@0: michael@0: mDeviceContext->Unmap(mClearVB, 0); michael@0: michael@0: // Apply state michael@0: mDeviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); michael@0: mDeviceContext->OMSetDepthStencilState(dsState, stencilClear); michael@0: mDeviceContext->RSSetState(mScissorEnabled ? mClearScissorRS : mClearNoScissorRS); michael@0: michael@0: // Apply shaders michael@0: ID3D11PixelShader *pixelShader = usingExtendedDrawBuffers ? mClearMultiplePS : mClearSinglePS; michael@0: michael@0: mDeviceContext->IASetInputLayout(mClearIL); michael@0: mDeviceContext->VSSetShader(mClearVS, NULL, 0); michael@0: mDeviceContext->PSSetShader(pixelShader, NULL, 0); michael@0: mDeviceContext->GSSetShader(NULL, NULL, 0); michael@0: michael@0: // Apply vertex buffer michael@0: static UINT stride = sizeof(d3d11::PositionDepthColorVertex); michael@0: static UINT startIdx = 0; michael@0: mDeviceContext->IASetVertexBuffers(0, 1, &mClearVB, &stride, &startIdx); michael@0: mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); michael@0: michael@0: // Draw the clear quad michael@0: mDeviceContext->Draw(4, 0); michael@0: michael@0: // Clean up michael@0: markAllStateDirty(); michael@0: } michael@0: michael@0: void Renderer11::markAllStateDirty() michael@0: { michael@0: for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) michael@0: { michael@0: mAppliedRenderTargetSerials[rtIndex] = 0; michael@0: } michael@0: mAppliedDepthbufferSerial = 0; michael@0: mAppliedStencilbufferSerial = 0; michael@0: mDepthStencilInitialized = false; michael@0: mRenderTargetDescInitialized = false; michael@0: michael@0: for (int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++) michael@0: { michael@0: mForceSetVertexSamplerStates[i] = true; michael@0: mCurVertexTextureSerials[i] = 0; michael@0: } michael@0: for (int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++) michael@0: { michael@0: mForceSetPixelSamplerStates[i] = true; michael@0: mCurPixelTextureSerials[i] = 0; michael@0: } michael@0: michael@0: mForceSetBlendState = true; michael@0: mForceSetRasterState = true; michael@0: mForceSetDepthStencilState = true; michael@0: mForceSetScissor = true; michael@0: mForceSetViewport = true; michael@0: michael@0: mAppliedIBSerial = 0; michael@0: mAppliedStorageIBSerial = 0; michael@0: mAppliedIBOffset = 0; michael@0: michael@0: mAppliedProgramBinarySerial = 0; michael@0: memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); michael@0: memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); michael@0: michael@0: mInputLayoutCache.markDirty(); michael@0: michael@0: mCurrentVertexConstantBuffer = NULL; michael@0: mCurrentPixelConstantBuffer = NULL; michael@0: mCurrentGeometryConstantBuffer = NULL; michael@0: michael@0: mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; michael@0: } michael@0: michael@0: void Renderer11::releaseDeviceResources() michael@0: { michael@0: mStateCache.clear(); michael@0: mInputLayoutCache.clear(); michael@0: michael@0: delete mVertexDataManager; michael@0: mVertexDataManager = NULL; michael@0: michael@0: delete mIndexDataManager; michael@0: mIndexDataManager = NULL; michael@0: michael@0: delete mLineLoopIB; michael@0: mLineLoopIB = NULL; michael@0: michael@0: delete mTriangleFanIB; michael@0: mTriangleFanIB = NULL; michael@0: michael@0: SafeRelease(mCopyVB); michael@0: SafeRelease(mCopySampler); michael@0: SafeRelease(mCopyIL); michael@0: SafeRelease(mCopyIL); michael@0: SafeRelease(mCopyVS); michael@0: SafeRelease(mCopyRGBAPS); michael@0: SafeRelease(mCopyRGBPS); michael@0: SafeRelease(mCopyLumPS); michael@0: SafeRelease(mCopyLumAlphaPS); michael@0: michael@0: mCopyResourcesInitialized = false; michael@0: michael@0: SafeRelease(mClearVB); michael@0: SafeRelease(mClearIL); michael@0: SafeRelease(mClearVS); michael@0: SafeRelease(mClearSinglePS); michael@0: SafeRelease(mClearMultiplePS); michael@0: SafeRelease(mClearScissorRS); michael@0: SafeRelease(mClearNoScissorRS); michael@0: michael@0: mClearResourcesInitialized = false; michael@0: michael@0: SafeRelease(mDriverConstantBufferVS); michael@0: SafeRelease(mDriverConstantBufferPS); michael@0: SafeRelease(mSyncQuery); michael@0: } michael@0: michael@0: void Renderer11::notifyDeviceLost() michael@0: { michael@0: mDeviceLost = true; michael@0: mDisplay->notifyDeviceLost(); michael@0: } michael@0: michael@0: bool Renderer11::isDeviceLost() michael@0: { michael@0: return mDeviceLost; michael@0: } michael@0: michael@0: // set notify to true to broadcast a message to all contexts of the device loss michael@0: bool Renderer11::testDeviceLost(bool notify) michael@0: { michael@0: bool isLost = false; michael@0: michael@0: // GetRemovedReason is used to test if the device is removed michael@0: HRESULT result = mDevice->GetDeviceRemovedReason(); michael@0: isLost = d3d11::isDeviceLostError(result); michael@0: michael@0: if (isLost) michael@0: { michael@0: // Log error if this is a new device lost event michael@0: if (mDeviceLost == false) michael@0: { michael@0: ERR("The D3D11 device was removed: 0x%08X", result); michael@0: } michael@0: michael@0: // ensure we note the device loss -- michael@0: // we'll probably get this done again by notifyDeviceLost michael@0: // but best to remember it! michael@0: // Note that we don't want to clear the device loss status here michael@0: // -- this needs to be done by resetDevice michael@0: mDeviceLost = true; michael@0: if (notify) michael@0: { michael@0: notifyDeviceLost(); michael@0: } michael@0: } michael@0: michael@0: return isLost; michael@0: } michael@0: michael@0: bool Renderer11::testDeviceResettable() michael@0: { michael@0: // determine if the device is resettable by creating a dummy device michael@0: PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); michael@0: michael@0: if (D3D11CreateDevice == NULL) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: D3D_FEATURE_LEVEL featureLevels[] = michael@0: { michael@0: D3D_FEATURE_LEVEL_11_0, michael@0: D3D_FEATURE_LEVEL_10_1, michael@0: D3D_FEATURE_LEVEL_10_0, michael@0: }; michael@0: michael@0: ID3D11Device* dummyDevice; michael@0: D3D_FEATURE_LEVEL dummyFeatureLevel; michael@0: ID3D11DeviceContext* dummyContext; michael@0: michael@0: HRESULT result = D3D11CreateDevice(NULL, michael@0: D3D_DRIVER_TYPE_HARDWARE, michael@0: NULL, michael@0: #if defined(_DEBUG) michael@0: D3D11_CREATE_DEVICE_DEBUG, michael@0: #else michael@0: 0, michael@0: #endif michael@0: featureLevels, michael@0: ArraySize(featureLevels), michael@0: D3D11_SDK_VERSION, michael@0: &dummyDevice, michael@0: &dummyFeatureLevel, michael@0: &dummyContext); michael@0: michael@0: if (!mDevice || FAILED(result)) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: dummyContext->Release(); michael@0: dummyDevice->Release(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void Renderer11::release() michael@0: { michael@0: releaseDeviceResources(); michael@0: michael@0: if (mDxgiFactory) michael@0: { michael@0: mDxgiFactory->Release(); michael@0: mDxgiFactory = NULL; michael@0: } michael@0: michael@0: if (mDxgiAdapter) michael@0: { michael@0: mDxgiAdapter->Release(); michael@0: mDxgiAdapter = NULL; michael@0: } michael@0: michael@0: if (mDeviceContext) michael@0: { michael@0: mDeviceContext->ClearState(); michael@0: mDeviceContext->Flush(); michael@0: mDeviceContext->Release(); michael@0: mDeviceContext = NULL; michael@0: } michael@0: michael@0: if (mDevice) michael@0: { michael@0: mDevice->Release(); michael@0: mDevice = NULL; michael@0: } michael@0: michael@0: if (mD3d11Module) michael@0: { michael@0: FreeLibrary(mD3d11Module); michael@0: mD3d11Module = NULL; michael@0: } michael@0: michael@0: if (mDxgiModule) michael@0: { michael@0: FreeLibrary(mDxgiModule); michael@0: mDxgiModule = NULL; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::resetDevice() michael@0: { michael@0: // recreate everything michael@0: release(); michael@0: EGLint result = initialize(); michael@0: michael@0: if (result != EGL_SUCCESS) michael@0: { michael@0: ERR("Could not reinitialize D3D11 device: %08X", result); michael@0: return false; michael@0: } michael@0: michael@0: mDeviceLost = false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: DWORD Renderer11::getAdapterVendor() const michael@0: { michael@0: return mAdapterDescription.VendorId; michael@0: } michael@0: michael@0: std::string Renderer11::getRendererDescription() const michael@0: { michael@0: std::ostringstream rendererString; michael@0: michael@0: rendererString << mDescription; michael@0: rendererString << " Direct3D11"; michael@0: michael@0: rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel(); michael@0: rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel(); michael@0: michael@0: return rendererString.str(); michael@0: } michael@0: michael@0: GUID Renderer11::getAdapterIdentifier() const michael@0: { michael@0: // Use the adapter LUID as our adapter ID michael@0: // This number is local to a machine is only guaranteed to be unique between restarts michael@0: META_ASSERT(sizeof(LUID) <= sizeof(GUID)); michael@0: GUID adapterId = {0}; michael@0: memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID)); michael@0: return adapterId; michael@0: } michael@0: michael@0: bool Renderer11::getBGRATextureSupport() const michael@0: { michael@0: return mBGRATextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getDXT1TextureSupport() michael@0: { michael@0: return mDXT1TextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getDXT3TextureSupport() michael@0: { michael@0: return mDXT3TextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getDXT5TextureSupport() michael@0: { michael@0: return mDXT5TextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getDepthTextureSupport() const michael@0: { michael@0: return mDepthTextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getFloat32TextureSupport(bool *filtering, bool *renderable) michael@0: { michael@0: *renderable = mFloat32RenderSupport; michael@0: *filtering = mFloat32FilterSupport; michael@0: return mFloat32TextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getFloat16TextureSupport(bool *filtering, bool *renderable) michael@0: { michael@0: *renderable = mFloat16RenderSupport; michael@0: *filtering = mFloat16FilterSupport; michael@0: return mFloat16TextureSupport; michael@0: } michael@0: michael@0: bool Renderer11::getLuminanceTextureSupport() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: bool Renderer11::getLuminanceAlphaTextureSupport() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: bool Renderer11::getTextureFilterAnisotropySupport() const michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: float Renderer11::getTextureMaxAnisotropy() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: return D3D11_MAX_MAXANISOTROPY; michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return D3D10_MAX_MAXANISOTROPY; michael@0: default: UNREACHABLE(); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getEventQuerySupport() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: Range Renderer11::getViewportBounds() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: return Range(D3D11_VIEWPORT_BOUNDS_MIN, D3D11_VIEWPORT_BOUNDS_MAX); michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return Range(D3D10_VIEWPORT_BOUNDS_MIN, D3D10_VIEWPORT_BOUNDS_MAX); michael@0: default: UNREACHABLE(); michael@0: return Range(0, 0); michael@0: } michael@0: } michael@0: michael@0: unsigned int Renderer11::getMaxVertexTextureImageUnits() const michael@0: { michael@0: META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS); michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return MAX_TEXTURE_IMAGE_UNITS_VTF_SM4; michael@0: default: UNREACHABLE(); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: unsigned int Renderer11::getMaxCombinedTextureImageUnits() const michael@0: { michael@0: return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits(); michael@0: } michael@0: michael@0: unsigned int Renderer11::getReservedVertexUniformVectors() const michael@0: { michael@0: return 0; // Driver uniforms are stored in a separate constant buffer michael@0: } michael@0: michael@0: unsigned int Renderer11::getReservedFragmentUniformVectors() const michael@0: { michael@0: return 0; // Driver uniforms are stored in a separate constant buffer michael@0: } michael@0: michael@0: unsigned int Renderer11::getMaxVertexUniformVectors() const michael@0: { michael@0: META_ASSERT(MAX_VERTEX_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); michael@0: ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_10_0); michael@0: return MAX_VERTEX_UNIFORM_VECTORS_D3D11; michael@0: } michael@0: michael@0: unsigned int Renderer11::getMaxFragmentUniformVectors() const michael@0: { michael@0: META_ASSERT(MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); michael@0: ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_10_0); michael@0: return MAX_FRAGMENT_UNIFORM_VECTORS_D3D11; michael@0: } michael@0: michael@0: unsigned int Renderer11::getMaxVaryingVectors() const michael@0: { michael@0: META_ASSERT(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT); michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: return D3D11_VS_OUTPUT_REGISTER_COUNT; michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return D3D10_VS_OUTPUT_REGISTER_COUNT; michael@0: default: UNREACHABLE(); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getNonPower2TextureSupport() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return true; michael@0: default: UNREACHABLE(); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getOcclusionQuerySupport() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return true; michael@0: default: UNREACHABLE(); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getInstancingSupport() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return true; michael@0: default: UNREACHABLE(); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getShareHandleSupport() const michael@0: { michael@0: // We only currently support share handles with BGRA surfaces, because michael@0: // chrome needs BGRA. Once chrome fixes this, we should always support them. michael@0: // PIX doesn't seem to support using share handles, so disable them. michael@0: return getBGRATextureSupport() && !gl::perfActive(); michael@0: } michael@0: michael@0: bool Renderer11::getDerivativeInstructionSupport() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return true; michael@0: default: UNREACHABLE(); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getPostSubBufferSupport() const michael@0: { michael@0: // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2. michael@0: return false; michael@0: } michael@0: michael@0: int Renderer11::getMajorShaderModel() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 michael@0: case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 michael@0: case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4 michael@0: default: UNREACHABLE(); return 0; michael@0: } michael@0: } michael@0: michael@0: int Renderer11::getMinorShaderModel() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 michael@0: case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 michael@0: case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0 michael@0: default: UNREACHABLE(); return 0; michael@0: } michael@0: } michael@0: michael@0: float Renderer11::getMaxPointSize() const michael@0: { michael@0: // choose a reasonable maximum. we enforce this in the shader. michael@0: // (nb: on a Radeon 2600xt, DX9 reports a 256 max point size) michael@0: return 1024.0f; michael@0: } michael@0: michael@0: int Renderer11::getMaxViewportDimension() const michael@0: { michael@0: // Maximum viewport size must be at least as large as the largest render buffer (or larger). michael@0: // In our case return the maximum texture size, which is the maximum render buffer size. michael@0: META_ASSERT(D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2 - 1 <= D3D11_VIEWPORT_BOUNDS_MAX); michael@0: META_ASSERT(D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2 - 1 <= D3D10_VIEWPORT_BOUNDS_MAX); michael@0: michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384 michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192 michael@0: default: UNREACHABLE(); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: int Renderer11::getMaxTextureWidth() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384 michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192 michael@0: default: UNREACHABLE(); return 0; michael@0: } michael@0: } michael@0: michael@0: int Renderer11::getMaxTextureHeight() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384 michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192 michael@0: default: UNREACHABLE(); return 0; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::get32BitIndexSupport() const michael@0: { michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP >= 32; // true michael@0: default: UNREACHABLE(); return false; michael@0: } michael@0: } michael@0: michael@0: int Renderer11::getMinSwapInterval() const michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: int Renderer11::getMaxSwapInterval() const michael@0: { michael@0: return 4; michael@0: } michael@0: michael@0: int Renderer11::getMaxSupportedSamples() const michael@0: { michael@0: return mMaxSupportedSamples; michael@0: } michael@0: michael@0: int Renderer11::getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const michael@0: { michael@0: if (requested == 0) michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format); michael@0: if (iter != mMultisampleSupportMap.end()) michael@0: { michael@0: const MultisampleSupportInfo& info = iter->second; michael@0: for (unsigned int i = requested - 1; i < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) michael@0: { michael@0: if (info.qualityLevels[i] > 0) michael@0: { michael@0: return i + 1; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return -1; michael@0: } michael@0: michael@0: unsigned int Renderer11::getMaxRenderTargets() const michael@0: { michael@0: META_ASSERT(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); michael@0: META_ASSERT(D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS); michael@0: michael@0: switch (mFeatureLevel) michael@0: { michael@0: case D3D_FEATURE_LEVEL_11_0: michael@0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; // 8 michael@0: case D3D_FEATURE_LEVEL_10_1: michael@0: case D3D_FEATURE_LEVEL_10_0: michael@0: return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; // 8 michael@0: default: michael@0: UNREACHABLE(); michael@0: return 1; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) michael@0: { michael@0: if (source && dest) michael@0: { michael@0: TextureStorage11_2D *source11 = TextureStorage11_2D::makeTextureStorage11_2D(source->getStorageInstance()); michael@0: TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(dest->getStorageInstance()); michael@0: michael@0: mDeviceContext->CopyResource(dest11->getBaseTexture(), source11->getBaseTexture()); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool Renderer11::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source) michael@0: { michael@0: if (source && dest) michael@0: { michael@0: TextureStorage11_Cube *source11 = TextureStorage11_Cube::makeTextureStorage11_Cube(source->getStorageInstance()); michael@0: TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(dest->getStorageInstance()); michael@0: michael@0: mDeviceContext->CopyResource(dest11->getBaseTexture(), source11->getBaseTexture()); michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, michael@0: GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) michael@0: { michael@0: gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer(); michael@0: if (!colorbuffer) michael@0: { michael@0: ERR("Failed to retrieve the color buffer from the frame buffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); michael@0: if (!sourceRenderTarget) michael@0: { michael@0: ERR("Failed to retrieve the render target from the frame buffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); michael@0: if (!source) michael@0: { michael@0: ERR("Failed to retrieve the render target view from the render target."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); michael@0: if (!storage11) michael@0: { michael@0: ERR("Failed to retrieve the texture storage from the destination."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(level)); michael@0: if (!destRenderTarget) michael@0: { michael@0: ERR("Failed to retrieve the render target from the destination storage."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); michael@0: if (!dest) michael@0: { michael@0: ERR("Failed to retrieve the render target view from the destination render target."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: gl::Rectangle destRect; michael@0: destRect.x = xoffset; michael@0: destRect.y = yoffset; michael@0: destRect.width = sourceRect.width; michael@0: destRect.height = sourceRect.height; michael@0: michael@0: bool ret = copyTexture(source, sourceRect, sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), michael@0: dest, destRect, destRenderTarget->getWidth(), destRenderTarget->getHeight(), destFormat); michael@0: michael@0: return ret; michael@0: } michael@0: michael@0: bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, michael@0: GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) michael@0: { michael@0: gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer(); michael@0: if (!colorbuffer) michael@0: { michael@0: ERR("Failed to retrieve the color buffer from the frame buffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); michael@0: if (!sourceRenderTarget) michael@0: { michael@0: ERR("Failed to retrieve the render target from the frame buffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); michael@0: if (!source) michael@0: { michael@0: ERR("Failed to retrieve the render target view from the render target."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance()); michael@0: if (!storage11) michael@0: { michael@0: ERR("Failed to retrieve the texture storage from the destination."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(target, level)); michael@0: if (!destRenderTarget) michael@0: { michael@0: ERR("Failed to retrieve the render target from the destination storage."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); michael@0: if (!dest) michael@0: { michael@0: ERR("Failed to retrieve the render target view from the destination render target."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: gl::Rectangle destRect; michael@0: destRect.x = xoffset; michael@0: destRect.y = yoffset; michael@0: destRect.width = sourceRect.width; michael@0: destRect.height = sourceRect.height; michael@0: michael@0: bool ret = copyTexture(source, sourceRect, sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), michael@0: dest, destRect, destRenderTarget->getWidth(), destRenderTarget->getHeight(), destFormat); michael@0: michael@0: return ret; michael@0: } michael@0: michael@0: bool Renderer11::copyTexture(ID3D11ShaderResourceView *source, const gl::Rectangle &sourceArea, unsigned int sourceWidth, unsigned int sourceHeight, michael@0: ID3D11RenderTargetView *dest, const gl::Rectangle &destArea, unsigned int destWidth, unsigned int destHeight, GLenum destFormat) michael@0: { michael@0: HRESULT result; michael@0: michael@0: if (!mCopyResourcesInitialized) michael@0: { michael@0: ASSERT(!mCopyVB && !mCopySampler && !mCopyIL && !mCopyVS && !mCopyRGBAPS && !mCopyRGBPS && !mCopyLumPS && !mCopyLumAlphaPS); michael@0: michael@0: D3D11_BUFFER_DESC vbDesc; michael@0: vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; michael@0: vbDesc.Usage = D3D11_USAGE_DYNAMIC; michael@0: vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; michael@0: vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; michael@0: vbDesc.MiscFlags = 0; michael@0: vbDesc.StructureByteStride = 0; michael@0: michael@0: result = mDevice->CreateBuffer(&vbDesc, NULL, &mCopyVB); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyVB, "Renderer11 copy texture vertex buffer"); michael@0: michael@0: D3D11_SAMPLER_DESC samplerDesc; michael@0: samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; michael@0: samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; michael@0: samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; michael@0: samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; michael@0: samplerDesc.MipLODBias = 0.0f; michael@0: samplerDesc.MaxAnisotropy = 0; michael@0: samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; michael@0: samplerDesc.BorderColor[0] = 0.0f; michael@0: samplerDesc.BorderColor[1] = 0.0f; michael@0: samplerDesc.BorderColor[2] = 0.0f; michael@0: samplerDesc.BorderColor[3] = 0.0f; michael@0: samplerDesc.MinLOD = 0.0f; michael@0: samplerDesc.MaxLOD = 0.0f; michael@0: michael@0: result = mDevice->CreateSamplerState(&samplerDesc, &mCopySampler); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopySampler, "Renderer11 copy sampler"); michael@0: michael@0: D3D11_INPUT_ELEMENT_DESC quadLayout[] = michael@0: { michael@0: { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, michael@0: { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, michael@0: }; michael@0: michael@0: result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Passthrough, sizeof(g_VS_Passthrough), &mCopyIL); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyIL, "Renderer11 copy texture input layout"); michael@0: michael@0: result = mDevice->CreateVertexShader(g_VS_Passthrough, sizeof(g_VS_Passthrough), NULL, &mCopyVS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyVS, "Renderer11 copy texture vertex shader"); michael@0: michael@0: result = mDevice->CreatePixelShader(g_PS_PassthroughRGBA, sizeof(g_PS_PassthroughRGBA), NULL, &mCopyRGBAPS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyRGBAPS, "Renderer11 copy texture RGBA pixel shader"); michael@0: michael@0: result = mDevice->CreatePixelShader(g_PS_PassthroughRGB, sizeof(g_PS_PassthroughRGB), NULL, &mCopyRGBPS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyRGBPS, "Renderer11 copy texture RGB pixel shader"); michael@0: michael@0: result = mDevice->CreatePixelShader(g_PS_PassthroughLum, sizeof(g_PS_PassthroughLum), NULL, &mCopyLumPS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyLumPS, "Renderer11 copy texture luminance pixel shader"); michael@0: michael@0: result = mDevice->CreatePixelShader(g_PS_PassthroughLumAlpha, sizeof(g_PS_PassthroughLumAlpha), NULL, &mCopyLumAlphaPS); michael@0: ASSERT(SUCCEEDED(result)); michael@0: d3d11::SetDebugName(mCopyLumAlphaPS, "Renderer11 copy texture luminance alpha pixel shader"); michael@0: michael@0: mCopyResourcesInitialized = true; michael@0: } michael@0: michael@0: // Verify the source and destination area sizes michael@0: if (sourceArea.x < 0 || sourceArea.x + sourceArea.width > static_cast(sourceWidth) || michael@0: sourceArea.y < 0 || sourceArea.y + sourceArea.height > static_cast(sourceHeight) || michael@0: destArea.x < 0 || destArea.x + destArea.width > static_cast(destWidth) || michael@0: destArea.y < 0 || destArea.y + destArea.height > static_cast(destHeight)) michael@0: { michael@0: return gl::error(GL_INVALID_VALUE, false); michael@0: } michael@0: michael@0: // Set vertices michael@0: D3D11_MAPPED_SUBRESOURCE mappedResource; michael@0: result = mDeviceContext->Map(mCopyVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); michael@0: michael@0: // Create a quad in homogeneous coordinates michael@0: float x1 = (destArea.x / float(destWidth)) * 2.0f - 1.0f; michael@0: float y1 = ((destHeight - destArea.y - destArea.height) / float(destHeight)) * 2.0f - 1.0f; michael@0: float x2 = ((destArea.x + destArea.width) / float(destWidth)) * 2.0f - 1.0f; michael@0: float y2 = ((destHeight - destArea.y) / float(destHeight)) * 2.0f - 1.0f; michael@0: michael@0: float u1 = sourceArea.x / float(sourceWidth); michael@0: float v1 = sourceArea.y / float(sourceHeight); michael@0: float u2 = (sourceArea.x + sourceArea.width) / float(sourceWidth); michael@0: float v2 = (sourceArea.y + sourceArea.height) / float(sourceHeight); michael@0: michael@0: d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); michael@0: d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); michael@0: d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); michael@0: d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); michael@0: michael@0: mDeviceContext->Unmap(mCopyVB, 0); michael@0: michael@0: static UINT stride = sizeof(d3d11::PositionTexCoordVertex); michael@0: static UINT startIdx = 0; michael@0: mDeviceContext->IASetVertexBuffers(0, 1, &mCopyVB, &stride, &startIdx); michael@0: michael@0: // Apply state michael@0: mDeviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); michael@0: mDeviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); michael@0: mDeviceContext->RSSetState(NULL); michael@0: michael@0: // Apply shaders michael@0: mDeviceContext->IASetInputLayout(mCopyIL); michael@0: mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); michael@0: mDeviceContext->VSSetShader(mCopyVS, NULL, 0); michael@0: michael@0: ID3D11PixelShader *ps = NULL; michael@0: switch(destFormat) michael@0: { michael@0: case GL_RGBA: ps = mCopyRGBAPS; break; michael@0: case GL_RGB: ps = mCopyRGBPS; break; michael@0: case GL_ALPHA: ps = mCopyRGBAPS; break; michael@0: case GL_BGRA_EXT: ps = mCopyRGBAPS; break; michael@0: case GL_LUMINANCE: ps = mCopyLumPS; break; michael@0: case GL_LUMINANCE_ALPHA: ps = mCopyLumAlphaPS; break; michael@0: default: UNREACHABLE(); ps = NULL; break; michael@0: } michael@0: michael@0: mDeviceContext->PSSetShader(ps, NULL, 0); michael@0: mDeviceContext->GSSetShader(NULL, NULL, 0); michael@0: michael@0: // Unset the currently bound shader resource to avoid conflicts michael@0: static ID3D11ShaderResourceView *const nullSRV = NULL; michael@0: mDeviceContext->PSSetShaderResources(0, 1, &nullSRV); michael@0: michael@0: // Apply render target michael@0: setOneTimeRenderTarget(dest); michael@0: michael@0: // Set the viewport michael@0: D3D11_VIEWPORT viewport; michael@0: viewport.TopLeftX = 0; michael@0: viewport.TopLeftY = 0; michael@0: viewport.Width = destWidth; michael@0: viewport.Height = destHeight; michael@0: viewport.MinDepth = 0.0f; michael@0: viewport.MaxDepth = 1.0f; michael@0: mDeviceContext->RSSetViewports(1, &viewport); michael@0: michael@0: // Apply textures michael@0: mDeviceContext->PSSetShaderResources(0, 1, &source); michael@0: mDeviceContext->PSSetSamplers(0, 1, &mCopySampler); michael@0: michael@0: // Draw the quad michael@0: mDeviceContext->Draw(4, 0); michael@0: michael@0: // Unbind textures and render targets and vertex buffer michael@0: mDeviceContext->PSSetShaderResources(0, 1, &nullSRV); michael@0: michael@0: unapplyRenderTargets(); michael@0: michael@0: UINT zero = 0; michael@0: ID3D11Buffer *const nullBuffer = NULL; michael@0: mDeviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); michael@0: michael@0: markAllStateDirty(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void Renderer11::unapplyRenderTargets() michael@0: { michael@0: setOneTimeRenderTarget(NULL); michael@0: } michael@0: michael@0: void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) michael@0: { michael@0: ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; michael@0: michael@0: rtvArray[0] = renderTargetView; michael@0: michael@0: mDeviceContext->OMSetRenderTargets(getMaxRenderTargets(), rtvArray, NULL); michael@0: michael@0: // Do not preserve the serial for this one-time-use render target michael@0: for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) michael@0: { michael@0: mAppliedRenderTargetSerials[rtIndex] = 0; michael@0: } michael@0: } michael@0: michael@0: RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth) michael@0: { michael@0: SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); michael@0: RenderTarget11 *renderTarget = NULL; michael@0: michael@0: if (depth) michael@0: { michael@0: // Note: depth stencil may be NULL for 0 sized surfaces michael@0: renderTarget = new RenderTarget11(this, swapChain11->getDepthStencil(), michael@0: swapChain11->getDepthStencilTexture(), NULL, michael@0: swapChain11->getWidth(), swapChain11->getHeight()); michael@0: } michael@0: else michael@0: { michael@0: // Note: render target may be NULL for 0 sized surfaces michael@0: renderTarget = new RenderTarget11(this, swapChain11->getRenderTarget(), michael@0: swapChain11->getOffscreenTexture(), michael@0: swapChain11->getRenderTargetShaderResource(), michael@0: swapChain11->getWidth(), swapChain11->getHeight()); michael@0: } michael@0: return renderTarget; michael@0: } michael@0: michael@0: RenderTarget *Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth) michael@0: { michael@0: RenderTarget11 *renderTarget = new RenderTarget11(this, width, height, format, samples, depth); michael@0: return renderTarget; michael@0: } michael@0: michael@0: ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type) michael@0: { michael@0: ShaderExecutable11 *executable = NULL; michael@0: michael@0: switch (type) michael@0: { michael@0: case rx::SHADER_VERTEX: michael@0: { michael@0: ID3D11VertexShader *vshader = NULL; michael@0: HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vshader); michael@0: ASSERT(SUCCEEDED(result)); michael@0: michael@0: if (vshader) michael@0: { michael@0: executable = new ShaderExecutable11(function, length, vshader); michael@0: } michael@0: } michael@0: break; michael@0: case rx::SHADER_PIXEL: michael@0: { michael@0: ID3D11PixelShader *pshader = NULL; michael@0: HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pshader); michael@0: ASSERT(SUCCEEDED(result)); michael@0: michael@0: if (pshader) michael@0: { michael@0: executable = new ShaderExecutable11(function, length, pshader); michael@0: } michael@0: } michael@0: break; michael@0: case rx::SHADER_GEOMETRY: michael@0: { michael@0: ID3D11GeometryShader *gshader = NULL; michael@0: HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &gshader); michael@0: ASSERT(SUCCEEDED(result)); michael@0: michael@0: if (gshader) michael@0: { michael@0: executable = new ShaderExecutable11(function, length, gshader); michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: UNREACHABLE(); michael@0: break; michael@0: } michael@0: michael@0: return executable; michael@0: } michael@0: michael@0: ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type) michael@0: { michael@0: const char *profile = NULL; michael@0: michael@0: switch (type) michael@0: { michael@0: case rx::SHADER_VERTEX: michael@0: profile = "vs_4_0"; michael@0: break; michael@0: case rx::SHADER_PIXEL: michael@0: profile = "ps_4_0"; michael@0: break; michael@0: case rx::SHADER_GEOMETRY: michael@0: profile = "gs_4_0"; michael@0: break; michael@0: default: michael@0: UNREACHABLE(); michael@0: return NULL; michael@0: } michael@0: michael@0: ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, D3DCOMPILE_OPTIMIZATION_LEVEL0, false); michael@0: if (!binary) michael@0: return NULL; michael@0: michael@0: ShaderExecutable *executable = loadExecutable((DWORD *)binary->GetBufferPointer(), binary->GetBufferSize(), type); michael@0: binary->Release(); michael@0: michael@0: return executable; michael@0: } michael@0: michael@0: VertexBuffer *Renderer11::createVertexBuffer() michael@0: { michael@0: return new VertexBuffer11(this); michael@0: } michael@0: michael@0: IndexBuffer *Renderer11::createIndexBuffer() michael@0: { michael@0: return new IndexBuffer11(this); michael@0: } michael@0: michael@0: BufferStorage *Renderer11::createBufferStorage() michael@0: { michael@0: return new BufferStorage11(this); michael@0: } michael@0: michael@0: QueryImpl *Renderer11::createQuery(GLenum type) michael@0: { michael@0: return new Query11(this, type); michael@0: } michael@0: michael@0: FenceImpl *Renderer11::createFence() michael@0: { michael@0: return new Fence11(this); michael@0: } michael@0: michael@0: bool Renderer11::getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource) michael@0: { michael@0: ASSERT(colorbuffer != NULL); michael@0: michael@0: RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget()); michael@0: if (renderTarget) michael@0: { michael@0: *subresourceIndex = renderTarget->getSubresourceIndex(); michael@0: michael@0: ID3D11RenderTargetView *colorBufferRTV = renderTarget->getRenderTargetView(); michael@0: if (colorBufferRTV) michael@0: { michael@0: ID3D11Resource *textureResource = NULL; michael@0: colorBufferRTV->GetResource(&textureResource); michael@0: michael@0: if (textureResource) michael@0: { michael@0: HRESULT result = textureResource->QueryInterface(IID_ID3D11Texture2D, (void**)resource); michael@0: textureResource->Release(); michael@0: michael@0: if (SUCCEEDED(result)) michael@0: { michael@0: return true; michael@0: } michael@0: else michael@0: { michael@0: ERR("Failed to extract the ID3D11Texture2D from the render target resource, " michael@0: "HRESULT: 0x%X.", result); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, michael@0: bool blitRenderTarget, bool blitDepthStencil) michael@0: { michael@0: if (blitRenderTarget) michael@0: { michael@0: gl::Renderbuffer *readBuffer = readTarget->getReadColorbuffer(); michael@0: michael@0: if (!readBuffer) michael@0: { michael@0: ERR("Failed to retrieve the read buffer from the read framebuffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget *readRenderTarget = readBuffer->getRenderTarget(); michael@0: michael@0: for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) michael@0: { michael@0: if (drawTarget->isEnabledColorAttachment(colorAttachment)) michael@0: { michael@0: gl::Renderbuffer *drawBuffer = drawTarget->getColorbuffer(colorAttachment); michael@0: michael@0: if (!drawBuffer) michael@0: { michael@0: ERR("Failed to retrieve the draw buffer from the draw framebuffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget *drawRenderTarget = drawBuffer->getRenderTarget(); michael@0: michael@0: if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, false)) michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (blitDepthStencil) michael@0: { michael@0: gl::Renderbuffer *readBuffer = readTarget->getDepthOrStencilbuffer(); michael@0: gl::Renderbuffer *drawBuffer = drawTarget->getDepthOrStencilbuffer(); michael@0: michael@0: if (!readBuffer) michael@0: { michael@0: ERR("Failed to retrieve the read depth-stencil buffer from the read framebuffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: if (!drawBuffer) michael@0: { michael@0: ERR("Failed to retrieve the draw depth-stencil buffer from the draw framebuffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: RenderTarget *readRenderTarget = readBuffer->getDepthStencil(); michael@0: RenderTarget *drawRenderTarget = drawBuffer->getDepthStencil(); michael@0: michael@0: if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, true)) michael@0: { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, michael@0: GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) michael@0: { michael@0: ID3D11Texture2D *colorBufferTexture = NULL; michael@0: unsigned int subresourceIndex = 0; michael@0: michael@0: gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer(); michael@0: michael@0: if (colorbuffer && getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) michael@0: { michael@0: gl::Rectangle area; michael@0: area.x = x; michael@0: area.y = y; michael@0: area.width = width; michael@0: area.height = height; michael@0: michael@0: readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, michael@0: packReverseRowOrder, packAlignment, pixels); michael@0: michael@0: colorBufferTexture->Release(); michael@0: colorBufferTexture = NULL; michael@0: } michael@0: } michael@0: michael@0: Image *Renderer11::createImage() michael@0: { michael@0: return new Image11(); michael@0: } michael@0: michael@0: void Renderer11::generateMipmap(Image *dest, Image *src) michael@0: { michael@0: Image11 *dest11 = Image11::makeImage11(dest); michael@0: Image11 *src11 = Image11::makeImage11(src); michael@0: Image11::generateMipmap(dest11, src11); michael@0: } michael@0: michael@0: TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain) michael@0: { michael@0: SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); michael@0: return new TextureStorage11_2D(this, swapChain11); michael@0: } michael@0: michael@0: TextureStorage *Renderer11::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) michael@0: { michael@0: return new TextureStorage11_2D(this, levels, internalformat, usage, forceRenderable, width, height); michael@0: } michael@0: michael@0: TextureStorage *Renderer11::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) michael@0: { michael@0: return new TextureStorage11_Cube(this, levels, internalformat, usage, forceRenderable, size); michael@0: } michael@0: michael@0: static inline unsigned int getFastPixelCopySize(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType) michael@0: { michael@0: if (sourceFormat == DXGI_FORMAT_A8_UNORM && michael@0: destFormat == GL_ALPHA && michael@0: destType == GL_UNSIGNED_BYTE) michael@0: { michael@0: return 1; michael@0: } michael@0: else if (sourceFormat == DXGI_FORMAT_R8G8B8A8_UNORM && michael@0: destFormat == GL_RGBA && michael@0: destType == GL_UNSIGNED_BYTE) michael@0: { michael@0: return 4; michael@0: } michael@0: else if (sourceFormat == DXGI_FORMAT_B8G8R8A8_UNORM && michael@0: destFormat == GL_BGRA_EXT && michael@0: destType == GL_UNSIGNED_BYTE) michael@0: { michael@0: return 4; michael@0: } michael@0: else if (sourceFormat == DXGI_FORMAT_R16G16B16A16_FLOAT && michael@0: destFormat == GL_RGBA && michael@0: destType == GL_HALF_FLOAT_OES) michael@0: { michael@0: return 8; michael@0: } michael@0: else if (sourceFormat == DXGI_FORMAT_R32G32B32_FLOAT && michael@0: destFormat == GL_RGB && michael@0: destType == GL_FLOAT) michael@0: { michael@0: return 12; michael@0: } michael@0: else if (sourceFormat == DXGI_FORMAT_R32G32B32A32_FLOAT && michael@0: destFormat == GL_RGBA && michael@0: destType == GL_FLOAT) michael@0: { michael@0: return 16; michael@0: } michael@0: else michael@0: { michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: static inline void readPixelColor(const unsigned char *data, DXGI_FORMAT format, unsigned int x, michael@0: unsigned int y, int inputPitch, gl::Color *outColor) michael@0: { michael@0: switch (format) michael@0: { michael@0: case DXGI_FORMAT_R8G8B8A8_UNORM: michael@0: { michael@0: unsigned int rgba = *reinterpret_cast(data + 4 * x + y * inputPitch); michael@0: outColor->red = (rgba & 0x000000FF) * (1.0f / 0x000000FF); michael@0: outColor->green = (rgba & 0x0000FF00) * (1.0f / 0x0000FF00); michael@0: outColor->blue = (rgba & 0x00FF0000) * (1.0f / 0x00FF0000); michael@0: outColor->alpha = (rgba & 0xFF000000) * (1.0f / 0xFF000000); michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_A8_UNORM: michael@0: { michael@0: outColor->red = 0.0f; michael@0: outColor->green = 0.0f; michael@0: outColor->blue = 0.0f; michael@0: outColor->alpha = *(data + x + y * inputPitch) / 255.0f; michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R32G32B32A32_FLOAT: michael@0: { michael@0: outColor->red = *(reinterpret_cast(data + 16 * x + y * inputPitch) + 0); michael@0: outColor->green = *(reinterpret_cast(data + 16 * x + y * inputPitch) + 1); michael@0: outColor->blue = *(reinterpret_cast(data + 16 * x + y * inputPitch) + 2); michael@0: outColor->alpha = *(reinterpret_cast(data + 16 * x + y * inputPitch) + 3); michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R32G32B32_FLOAT: michael@0: { michael@0: outColor->red = *(reinterpret_cast(data + 12 * x + y * inputPitch) + 0); michael@0: outColor->green = *(reinterpret_cast(data + 12 * x + y * inputPitch) + 1); michael@0: outColor->blue = *(reinterpret_cast(data + 12 * x + y * inputPitch) + 2); michael@0: outColor->alpha = 1.0f; michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R16G16B16A16_FLOAT: michael@0: { michael@0: outColor->red = gl::float16ToFloat32(*(reinterpret_cast(data + 8 * x + y * inputPitch) + 0)); michael@0: outColor->green = gl::float16ToFloat32(*(reinterpret_cast(data + 8 * x + y * inputPitch) + 1)); michael@0: outColor->blue = gl::float16ToFloat32(*(reinterpret_cast(data + 8 * x + y * inputPitch) + 2)); michael@0: outColor->alpha = gl::float16ToFloat32(*(reinterpret_cast(data + 8 * x + y * inputPitch) + 3)); michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_B8G8R8A8_UNORM: michael@0: { michael@0: unsigned int bgra = *reinterpret_cast(data + 4 * x + y * inputPitch); michael@0: outColor->red = (bgra & 0x00FF0000) * (1.0f / 0x00FF0000); michael@0: outColor->blue = (bgra & 0x000000FF) * (1.0f / 0x000000FF); michael@0: outColor->green = (bgra & 0x0000FF00) * (1.0f / 0x0000FF00); michael@0: outColor->alpha = (bgra & 0xFF000000) * (1.0f / 0xFF000000); michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R8_UNORM: michael@0: { michael@0: outColor->red = *(data + x + y * inputPitch) / 255.0f; michael@0: outColor->green = 0.0f; michael@0: outColor->blue = 0.0f; michael@0: outColor->alpha = 1.0f; michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R8G8_UNORM: michael@0: { michael@0: unsigned short rg = *reinterpret_cast(data + 2 * x + y * inputPitch); michael@0: michael@0: outColor->red = (rg & 0xFF00) * (1.0f / 0xFF00); michael@0: outColor->green = (rg & 0x00FF) * (1.0f / 0x00FF); michael@0: outColor->blue = 0.0f; michael@0: outColor->alpha = 1.0f; michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R16_FLOAT: michael@0: { michael@0: outColor->red = gl::float16ToFloat32(*reinterpret_cast(data + 2 * x + y * inputPitch)); michael@0: outColor->green = 0.0f; michael@0: outColor->blue = 0.0f; michael@0: outColor->alpha = 1.0f; michael@0: } michael@0: break; michael@0: michael@0: case DXGI_FORMAT_R16G16_FLOAT: michael@0: { michael@0: outColor->red = gl::float16ToFloat32(*(reinterpret_cast(data + 4 * x + y * inputPitch) + 0)); michael@0: outColor->green = gl::float16ToFloat32(*(reinterpret_cast(data + 4 * x + y * inputPitch) + 1)); michael@0: outColor->blue = 0.0f; michael@0: outColor->alpha = 1.0f; michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: ERR("ReadPixelColor not implemented for DXGI format %u.", format); michael@0: UNIMPLEMENTED(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: static inline void writePixelColor(const gl::Color &color, GLenum format, GLenum type, unsigned int x, michael@0: unsigned int y, int outputPitch, void *outData) michael@0: { michael@0: unsigned char* byteData = reinterpret_cast(outData); michael@0: unsigned short* shortData = reinterpret_cast(outData); michael@0: michael@0: switch (format) michael@0: { michael@0: case GL_RGBA: michael@0: switch (type) michael@0: { michael@0: case GL_UNSIGNED_BYTE: michael@0: byteData[4 * x + y * outputPitch + 0] = static_cast(255 * color.red + 0.5f); michael@0: byteData[4 * x + y * outputPitch + 1] = static_cast(255 * color.green + 0.5f); michael@0: byteData[4 * x + y * outputPitch + 2] = static_cast(255 * color.blue + 0.5f); michael@0: byteData[4 * x + y * outputPitch + 3] = static_cast(255 * color.alpha + 0.5f); michael@0: break; michael@0: michael@0: default: michael@0: ERR("WritePixelColor not implemented for format GL_RGBA and type 0x%X.", type); michael@0: UNIMPLEMENTED(); michael@0: break; michael@0: } michael@0: break; michael@0: michael@0: case GL_BGRA_EXT: michael@0: switch (type) michael@0: { michael@0: case GL_UNSIGNED_BYTE: michael@0: byteData[4 * x + y * outputPitch + 0] = static_cast(255 * color.blue + 0.5f); michael@0: byteData[4 * x + y * outputPitch + 1] = static_cast(255 * color.green + 0.5f); michael@0: byteData[4 * x + y * outputPitch + 2] = static_cast(255 * color.red + 0.5f); michael@0: byteData[4 * x + y * outputPitch + 3] = static_cast(255 * color.alpha + 0.5f); michael@0: break; michael@0: michael@0: case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: michael@0: // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section michael@0: // this type is packed as follows: michael@0: // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 michael@0: // -------------------------------------------------------------------------------- michael@0: // | 4th | 3rd | 2nd | 1st component | michael@0: // -------------------------------------------------------------------------------- michael@0: // in the case of BGRA_EXT, B is the first component, G the second, and so forth. michael@0: shortData[x + y * outputPitch / sizeof(unsigned short)] = michael@0: (static_cast(15 * color.alpha + 0.5f) << 12) | michael@0: (static_cast(15 * color.red + 0.5f) << 8) | michael@0: (static_cast(15 * color.green + 0.5f) << 4) | michael@0: (static_cast(15 * color.blue + 0.5f) << 0); michael@0: break; michael@0: michael@0: case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: michael@0: // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section michael@0: // this type is packed as follows: michael@0: // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 michael@0: // -------------------------------------------------------------------------------- michael@0: // | 4th | 3rd | 2nd | 1st component | michael@0: // -------------------------------------------------------------------------------- michael@0: // in the case of BGRA_EXT, B is the first component, G the second, and so forth. michael@0: shortData[x + y * outputPitch / sizeof(unsigned short)] = michael@0: (static_cast( color.alpha + 0.5f) << 15) | michael@0: (static_cast(31 * color.red + 0.5f) << 10) | michael@0: (static_cast(31 * color.green + 0.5f) << 5) | michael@0: (static_cast(31 * color.blue + 0.5f) << 0); michael@0: break; michael@0: michael@0: default: michael@0: ERR("WritePixelColor not implemented for format GL_BGRA_EXT and type 0x%X.", type); michael@0: UNIMPLEMENTED(); michael@0: break; michael@0: } michael@0: break; michael@0: michael@0: case GL_RGB: michael@0: switch (type) michael@0: { michael@0: case GL_UNSIGNED_SHORT_5_6_5: michael@0: shortData[x + y * outputPitch / sizeof(unsigned short)] = michael@0: (static_cast(31 * color.blue + 0.5f) << 0) | michael@0: (static_cast(63 * color.green + 0.5f) << 5) | michael@0: (static_cast(31 * color.red + 0.5f) << 11); michael@0: break; michael@0: michael@0: case GL_UNSIGNED_BYTE: michael@0: byteData[3 * x + y * outputPitch + 0] = static_cast(255 * color.red + 0.5f); michael@0: byteData[3 * x + y * outputPitch + 1] = static_cast(255 * color.green + 0.5f); michael@0: byteData[3 * x + y * outputPitch + 2] = static_cast(255 * color.blue + 0.5f); michael@0: break; michael@0: michael@0: default: michael@0: ERR("WritePixelColor not implemented for format GL_RGB and type 0x%X.", type); michael@0: UNIMPLEMENTED(); michael@0: break; michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: ERR("WritePixelColor not implemented for format 0x%X.", format); michael@0: UNIMPLEMENTED(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, michael@0: GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder, michael@0: GLint packAlignment, void *pixels) michael@0: { michael@0: D3D11_TEXTURE2D_DESC textureDesc; michael@0: texture->GetDesc(&textureDesc); michael@0: michael@0: D3D11_TEXTURE2D_DESC stagingDesc; michael@0: stagingDesc.Width = area.width; michael@0: stagingDesc.Height = area.height; michael@0: stagingDesc.MipLevels = 1; michael@0: stagingDesc.ArraySize = 1; michael@0: stagingDesc.Format = textureDesc.Format; michael@0: stagingDesc.SampleDesc.Count = 1; michael@0: stagingDesc.SampleDesc.Quality = 0; michael@0: stagingDesc.Usage = D3D11_USAGE_STAGING; michael@0: stagingDesc.BindFlags = 0; michael@0: stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; michael@0: stagingDesc.MiscFlags = 0; michael@0: michael@0: ID3D11Texture2D* stagingTex = NULL; michael@0: HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex); michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Failed to create staging texture for readPixels, HRESULT: 0x%X.", result); michael@0: return; michael@0: } michael@0: michael@0: ID3D11Texture2D* srcTex = NULL; michael@0: if (textureDesc.SampleDesc.Count > 1) michael@0: { michael@0: D3D11_TEXTURE2D_DESC resolveDesc; michael@0: resolveDesc.Width = textureDesc.Width; michael@0: resolveDesc.Height = textureDesc.Height; michael@0: resolveDesc.MipLevels = 1; michael@0: resolveDesc.ArraySize = 1; michael@0: resolveDesc.Format = textureDesc.Format; michael@0: resolveDesc.SampleDesc.Count = 1; michael@0: resolveDesc.SampleDesc.Quality = 0; michael@0: resolveDesc.Usage = D3D11_USAGE_DEFAULT; michael@0: resolveDesc.BindFlags = 0; michael@0: resolveDesc.CPUAccessFlags = 0; michael@0: resolveDesc.MiscFlags = 0; michael@0: michael@0: result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex); michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Failed to create resolve texture for readPixels, HRESULT: 0x%X.", result); michael@0: stagingTex->Release(); michael@0: return; michael@0: } michael@0: michael@0: mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format); michael@0: subResource = 0; michael@0: } michael@0: else michael@0: { michael@0: srcTex = texture; michael@0: srcTex->AddRef(); michael@0: } michael@0: michael@0: D3D11_BOX srcBox; michael@0: srcBox.left = area.x; michael@0: srcBox.right = area.x + area.width; michael@0: srcBox.top = area.y; michael@0: srcBox.bottom = area.y + area.height; michael@0: srcBox.front = 0; michael@0: srcBox.back = 1; michael@0: michael@0: mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); michael@0: michael@0: srcTex->Release(); michael@0: srcTex = NULL; michael@0: michael@0: D3D11_MAPPED_SUBRESOURCE mapping; michael@0: mDeviceContext->Map(stagingTex, 0, D3D11_MAP_READ, 0, &mapping); michael@0: michael@0: unsigned char *source; michael@0: int inputPitch; michael@0: if (packReverseRowOrder) michael@0: { michael@0: source = static_cast(mapping.pData) + mapping.RowPitch * (area.height - 1); michael@0: inputPitch = -static_cast(mapping.RowPitch); michael@0: } michael@0: else michael@0: { michael@0: source = static_cast(mapping.pData); michael@0: inputPitch = static_cast(mapping.RowPitch); michael@0: } michael@0: michael@0: unsigned int fastPixelSize = getFastPixelCopySize(textureDesc.Format, format, type); michael@0: if (fastPixelSize != 0) michael@0: { michael@0: unsigned char *dest = static_cast(pixels); michael@0: for (int j = 0; j < area.height; j++) michael@0: { michael@0: memcpy(dest + j * outputPitch, source + j * inputPitch, area.width * fastPixelSize); michael@0: } michael@0: } michael@0: else if (textureDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM && michael@0: format == GL_RGBA && michael@0: type == GL_UNSIGNED_BYTE) michael@0: { michael@0: // Fast path for swapping red with blue michael@0: unsigned char *dest = static_cast(pixels); michael@0: michael@0: for (int j = 0; j < area.height; j++) michael@0: { michael@0: for (int i = 0; i < area.width; i++) michael@0: { michael@0: unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch); michael@0: *(unsigned int*)(dest + 4 * i + j * outputPitch) = michael@0: (argb & 0xFF00FF00) | // Keep alpha and green michael@0: (argb & 0x00FF0000) >> 16 | // Move red to blue michael@0: (argb & 0x000000FF) << 16; // Move blue to red michael@0: } michael@0: } michael@0: } michael@0: else michael@0: { michael@0: gl::Color pixelColor; michael@0: for (int j = 0; j < area.height; j++) michael@0: { michael@0: for (int i = 0; i < area.width; i++) michael@0: { michael@0: readPixelColor(source, textureDesc.Format, i, j, inputPitch, &pixelColor); michael@0: writePixelColor(pixelColor, format, type, i, j, outputPitch, pixels); michael@0: } michael@0: } michael@0: } michael@0: michael@0: mDeviceContext->Unmap(stagingTex, 0); michael@0: michael@0: stagingTex->Release(); michael@0: stagingTex = NULL; michael@0: } michael@0: michael@0: bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, michael@0: RenderTarget *drawRenderTarget, bool wholeBufferCopy) michael@0: { michael@0: ASSERT(readRect.width == drawRect.width && readRect.height == drawRect.height); michael@0: michael@0: RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); michael@0: if (!drawRenderTarget) michael@0: { michael@0: ERR("Failed to retrieve the draw render target from the draw framebuffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: ID3D11Texture2D *drawTexture = drawRenderTarget11->getTexture(); michael@0: unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); michael@0: michael@0: RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); michael@0: if (!readRenderTarget) michael@0: { michael@0: ERR("Failed to retrieve the read render target from the read framebuffer."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: ID3D11Texture2D *readTexture = NULL; michael@0: unsigned int readSubresource = 0; michael@0: if (readRenderTarget->getSamples() > 0) michael@0: { michael@0: readTexture = resolveMultisampledTexture(readRenderTarget11->getTexture(), readRenderTarget11->getSubresourceIndex()); michael@0: readSubresource = 0; michael@0: } michael@0: else michael@0: { michael@0: readTexture = readRenderTarget11->getTexture(); michael@0: readTexture->AddRef(); michael@0: readSubresource = readRenderTarget11->getSubresourceIndex(); michael@0: } michael@0: michael@0: if (!readTexture) michael@0: { michael@0: ERR("Failed to retrieve the read render target view from the read render target."); michael@0: return gl::error(GL_OUT_OF_MEMORY, false); michael@0: } michael@0: michael@0: D3D11_BOX readBox; michael@0: readBox.left = readRect.x; michael@0: readBox.right = readRect.x + readRect.width; michael@0: readBox.top = readRect.y; michael@0: readBox.bottom = readRect.y + readRect.height; michael@0: readBox.front = 0; michael@0: readBox.back = 1; michael@0: michael@0: // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox michael@0: // We also require complete framebuffer copies for depth-stencil blit. michael@0: D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; michael@0: michael@0: mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, drawRect.x, drawRect.y, 0, michael@0: readTexture, readSubresource, pSrcBox); michael@0: michael@0: SafeRelease(readTexture); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) michael@0: { michael@0: D3D11_TEXTURE2D_DESC textureDesc; michael@0: source->GetDesc(&textureDesc); michael@0: michael@0: if (textureDesc.SampleDesc.Count > 1) michael@0: { michael@0: D3D11_TEXTURE2D_DESC resolveDesc; michael@0: resolveDesc.Width = textureDesc.Width; michael@0: resolveDesc.Height = textureDesc.Height; michael@0: resolveDesc.MipLevels = 1; michael@0: resolveDesc.ArraySize = 1; michael@0: resolveDesc.Format = textureDesc.Format; michael@0: resolveDesc.SampleDesc.Count = 1; michael@0: resolveDesc.SampleDesc.Quality = 0; michael@0: resolveDesc.Usage = textureDesc.Usage; michael@0: resolveDesc.BindFlags = textureDesc.BindFlags; michael@0: resolveDesc.CPUAccessFlags = 0; michael@0: resolveDesc.MiscFlags = 0; michael@0: michael@0: ID3D11Texture2D *resolveTexture = NULL; michael@0: HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture); michael@0: if (FAILED(result)) michael@0: { michael@0: ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result); michael@0: return NULL; michael@0: } michael@0: michael@0: mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); michael@0: return resolveTexture; michael@0: } michael@0: else michael@0: { michael@0: source->AddRef(); michael@0: return source; michael@0: } michael@0: } michael@0: michael@0: bool Renderer11::getLUID(LUID *adapterLuid) const michael@0: { michael@0: adapterLuid->HighPart = 0; michael@0: adapterLuid->LowPart = 0; michael@0: michael@0: if (!mDxgiAdapter) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: DXGI_ADAPTER_DESC adapterDesc; michael@0: if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc))) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: *adapterLuid = adapterDesc.AdapterLuid; michael@0: return true; michael@0: } michael@0: michael@0: }