diff options
Diffstat (limited to 'Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp')
-rw-r--r-- | Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp | 2622 |
1 files changed, 1311 insertions, 1311 deletions
diff --git a/Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp b/Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp index 64887dd..a1a567a 100644 --- a/Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp +++ b/Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp @@ -1,1311 +1,1311 @@ -/************************************************************************************
-
-Filename : RenderTiny_D3D1x.cpp
-Content : RenderDevice implementation for D3DX10/11.
-Created : September 10, 2012
-Authors : Andrew Reisse
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-************************************************************************************/
-
-#include "Kernel/OVR_Log.h"
-#include "Kernel/OVR_Std.h"
-
-#include "RenderTiny_D3D1X_Device.h"
-
-#include <d3dcompiler.h>
-
-namespace OVR { namespace RenderTiny { namespace D3D10 {
-
-
-//-------------------------------------------------------------------------------------
-// Vertex format
-static D3D1x_(INPUT_ELEMENT_DESC) ModelVertexDesc[] =
-{
- {"Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, Pos), D3D1x_(INPUT_PER_VERTEX_DATA), 0},
- {"Color", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(Vertex, C), D3D1x_(INPUT_PER_VERTEX_DATA), 0},
- {"TexCoord", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(Vertex, U), D3D1x_(INPUT_PER_VERTEX_DATA), 0},
- {"Normal", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, Norm), D3D1x_(INPUT_PER_VERTEX_DATA), 0},
-};
-
-// These shaders are used to render the world, including lit vertex-colored and textured geometry.
-
-// Used for world geometry; has projection matrix.
-static const char* StdVertexShaderSrc =
- "float4x4 Proj;\n"
- "float4x4 View;\n"
- "struct Varyings\n"
- "{\n"
- " float4 Position : SV_Position;\n"
- " float4 Color : COLOR0;\n"
- " float2 TexCoord : TEXCOORD0;\n"
- " float3 Normal : NORMAL;\n"
- " float3 VPos : TEXCOORD4;\n"
- "};\n"
- "void main(in float4 Position : POSITION, in float4 Color : COLOR0, in float2 TexCoord : TEXCOORD0,"
- " in float3 Normal : NORMAL,\n"
- " out Varyings ov)\n"
- "{\n"
- " ov.Position = mul(Proj, mul(View, Position));\n"
- " ov.Normal = mul(View, Normal);\n"
- " ov.VPos = mul(View, Position);\n"
- " ov.TexCoord = TexCoord;\n"
- " ov.Color = Color;\n"
- "}\n";
-
-// Used for text/clearing; no projection.
-static const char* DirectVertexShaderSrc =
- "float4x4 View : register(c4);\n"
- "void main(in float4 Position : POSITION, in float4 Color : COLOR0,\n"
- " in float2 TexCoord : TEXCOORD0, in float3 Normal : NORMAL,\n"
- " out float4 oPosition : SV_Position, out float4 oColor : COLOR,\n"
- " out float2 oTexCoord : TEXCOORD0,"
- " out float3 oNormal : NORMAL)\n"
- "{\n"
- " oPosition = mul(View, Position);\n"
- " oTexCoord = TexCoord;\n"
- " oColor = Color;\n"
- " oNormal = mul(View, Normal);\n"
- "}\n";
-
-static const char* SolidPixelShaderSrc =
- "float4 Color;\n"
- "struct Varyings\n"
- "{\n"
- " float4 Position : SV_Position;\n"
- " float4 Color : COLOR0;\n"
- " float2 TexCoord : TEXCOORD0;\n"
- "};\n"
- "float4 main(in Varyings ov) : SV_Target\n"
- "{\n"
- " return Color;\n"
- "}\n";
-
-static const char* GouraudPixelShaderSrc =
- "struct Varyings\n"
- "{\n"
- " float4 Position : SV_Position;\n"
- " float4 Color : COLOR0;\n"
- " float2 TexCoord : TEXCOORD0;\n"
- "};\n"
- "float4 main(in Varyings ov) : SV_Target\n"
- "{\n"
- " return ov.Color;\n"
- "}\n";
-
-static const char* TexturePixelShaderSrc =
- "Texture2D Texture : register(t0);\n"
- "SamplerState Linear : register(s0);\n"
- "struct Varyings\n"
- "{\n"
- " float4 Position : SV_Position;\n"
- " float4 Color : COLOR0;\n"
- " float2 TexCoord : TEXCOORD0;\n"
- "};\n"
- "float4 main(in Varyings ov) : SV_Target\n"
- "{\n"
- " float4 color2 = ov.Color * Texture.Sample(Linear, ov.TexCoord);\n"
- " if (color2.a <= 0.4)\n"
- " discard;\n"
- " return color2;\n"
- "}\n";
-
-
-#define LIGHTING_COMMON \
- "cbuffer Lighting : register(b1)\n" \
- "{\n" \
- " float3 Ambient;\n" \
- " float3 LightPos[8];\n" \
- " float4 LightColor[8];\n" \
- " float LightCount;\n" \
- "};\n" \
- "struct Varyings\n" \
- "{\n" \
- " float4 Position : SV_Position;\n" \
- " float4 Color : COLOR0;\n" \
- " float2 TexCoord : TEXCOORD0;\n" \
- " float3 Normal : NORMAL;\n" \
- " float3 VPos : TEXCOORD4;\n" \
- "};\n" \
- "float4 DoLight(Varyings v)\n" \
- "{\n" \
- " float3 norm = normalize(v.Normal);\n" \
- " float3 light = Ambient;\n" \
- " for (uint i = 0; i < LightCount; i++)\n"\
- " {\n" \
- " float3 ltp = (LightPos[i] - v.VPos);\n" \
- " float ldist = dot(ltp,ltp);\n" \
- " ltp = normalize(ltp);\n" \
- " light += saturate(LightColor[i] * v.Color.rgb * dot(norm, ltp) / sqrt(ldist));\n"\
- " }\n" \
- " return float4(light, v.Color.a);\n" \
- "}\n"
-
-static const char* LitSolidPixelShaderSrc =
- LIGHTING_COMMON
- "float4 main(in Varyings ov) : SV_Target\n"
- "{\n"
- " return DoLight(ov) * ov.Color;\n"
- "}\n";
-
-static const char* LitTexturePixelShaderSrc =
- "Texture2D Texture : register(t0);\n"
- "SamplerState Linear : register(s0);\n"
- LIGHTING_COMMON
- "float4 main(in Varyings ov) : SV_Target\n"
- "{\n"
- " return DoLight(ov) * Texture.Sample(Linear, ov.TexCoord);\n"
- "}\n";
-
-
-//-------------------------------------------------------------------------------------
-// ***** Distortion Post-process Shaders
-
-static const char* PostProcessVertexShaderSrc =
- "float4x4 View : register(c4);\n"
- "float4x4 Texm : register(c8);\n"
- "void main(in float4 Position : POSITION, in float4 Color : COLOR0, in float2 TexCoord : TEXCOORD0,\n"
- " out float4 oPosition : SV_Position, out float4 oColor : COLOR, out float2 oTexCoord : TEXCOORD0)\n"
- "{\n"
- " oPosition = mul(View, Position);\n"
- " oTexCoord = mul(Texm, float4(TexCoord,0,1));\n"
- " oColor = Color;\n"
- "}\n";
-
-// Shader with just lens distortion correction.
-static const char* PostProcessPixelShaderSrc =
- "Texture2D Texture : register(t0);\n"
- "SamplerState Linear : register(s0);\n"
- "float2 LensCenter;\n"
- "float2 ScreenCenter;\n"
- "float2 Scale;\n"
- "float2 ScaleIn;\n"
- "float4 HmdWarpParam;\n"
- "\n"
-
- // Scales input texture coordinates for distortion.
- // ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be
- // larger due to aspect ratio.
- "float2 HmdWarp(float2 in01)\n"
- "{\n"
- " float2 theta = (in01 - LensCenter) * ScaleIn;\n" // Scales to [-1, 1]
- " float rSq = theta.x * theta.x + theta.y * theta.y;\n"
- " float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + "
- " HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);\n"
- " return LensCenter + Scale * theta1;\n"
- "}\n"
-
- "float4 main(in float4 oPosition : SV_Position, in float4 oColor : COLOR,\n"
- " in float2 oTexCoord : TEXCOORD0) : SV_Target\n"
- "{\n"
- " float2 tc = HmdWarp(oTexCoord);\n"
- " if (any(clamp(tc, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tc))\n"
- " return 0;\n"
- " return Texture.Sample(Linear, tc);\n"
- "}\n";
-
-// Shader with lens distortion and chromatic aberration correction.
-static const char* PostProcessPixelShaderWithChromAbSrc =
- "Texture2D Texture : register(t0);\n"
- "SamplerState Linear : register(s0);\n"
- "float2 LensCenter;\n"
- "float2 ScreenCenter;\n"
- "float2 Scale;\n"
- "float2 ScaleIn;\n"
- "float4 HmdWarpParam;\n"
- "float4 ChromAbParam;\n"
- "\n"
-
- // Scales input texture coordinates for distortion.
- // ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be
- // larger due to aspect ratio.
- "float4 main(in float4 oPosition : SV_Position, in float4 oColor : COLOR,\n"
- " in float2 oTexCoord : TEXCOORD0) : SV_Target\n"
- "{\n"
- " float2 theta = (oTexCoord - LensCenter) * ScaleIn;\n" // Scales to [-1, 1]
- " float rSq= theta.x * theta.x + theta.y * theta.y;\n"
- " float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + "
- " HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);\n"
- " \n"
- " // Detect whether blue texture coordinates are out of range since these will scaled out the furthest.\n"
- " float2 thetaBlue = theta1 * (ChromAbParam.z + ChromAbParam.w * rSq);\n"
- " float2 tcBlue = LensCenter + Scale * thetaBlue;\n"
- " if (any(clamp(tcBlue, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tcBlue))\n"
- " return 0;\n"
- " \n"
- " // Now do blue texture lookup.\n"
- " float blue = Texture.Sample(Linear, tcBlue).b;\n"
- " \n"
- " // Do green lookup (no scaling).\n"
- " float2 tcGreen = LensCenter + Scale * theta1;\n"
- " float green = Texture.Sample(Linear, tcGreen).g;\n"
- " \n"
- " // Do red scale and lookup.\n"
- " float2 thetaRed = theta1 * (ChromAbParam.x + ChromAbParam.y * rSq);\n"
- " float2 tcRed = LensCenter + Scale * thetaRed;\n"
- " float red = Texture.Sample(Linear, tcRed).r;\n"
- " \n"
- " return float4(red, green, blue, 1);\n"
- "}\n";
-
-
-static const char* VShaderSrcs[VShader_Count] =
-{
- DirectVertexShaderSrc,
- StdVertexShaderSrc,
- PostProcessVertexShaderSrc
-};
-static const char* FShaderSrcs[FShader_Count] =
-{
- SolidPixelShaderSrc,
- GouraudPixelShaderSrc,
- TexturePixelShaderSrc,
- PostProcessPixelShaderSrc,
- PostProcessPixelShaderWithChromAbSrc,
- LitSolidPixelShaderSrc,
- LitTexturePixelShaderSrc
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** Buffer
-
-Buffer::~Buffer()
-{
-}
-
-bool Buffer::Data(int use, const void *buffer, size_t size)
-{
- if (D3DBuffer && Size >= size)
- {
- if (Dynamic)
- {
- if (!buffer)
- return true;
-
- void* v = Map(0, size, Map_Discard);
- if (v)
- {
- memcpy(v, buffer, size);
- Unmap(v);
- return true;
- }
- }
- else
- {
- Ren->Context->UpdateSubresource(D3DBuffer, 0, NULL, buffer, 0, 0);
- return true;
- }
- }
- if (D3DBuffer)
- {
- D3DBuffer = NULL;
- Size = 0;
- Use = 0;
- Dynamic = 0;
- }
-
- D3D1x_(BUFFER_DESC) desc;
- memset(&desc, 0, sizeof(desc));
- if (use & Buffer_ReadOnly)
- {
- desc.Usage = D3D1x_(USAGE_IMMUTABLE);
- desc.CPUAccessFlags = 0;
- }
- else
- {
- desc.Usage = D3D1x_(USAGE_DYNAMIC);
- desc.CPUAccessFlags = D3D1x_(CPU_ACCESS_WRITE);
- Dynamic = 1;
- }
-
- switch(use & Buffer_TypeMask)
- {
- case Buffer_Vertex: desc.BindFlags = D3D1x_(BIND_VERTEX_BUFFER); break;
- case Buffer_Index: desc.BindFlags = D3D1x_(BIND_INDEX_BUFFER); break;
- case Buffer_Uniform:
- desc.BindFlags = D3D1x_(BIND_CONSTANT_BUFFER);
- size += ((size + 15) & ~15) - size;
- break;
- }
-
- desc.ByteWidth = (unsigned)size;
-
- D3D1x_(SUBRESOURCE_DATA) sr;
- sr.pSysMem = buffer;
- sr.SysMemPitch = 0;
- sr.SysMemSlicePitch = 0;
-
- HRESULT hr = Ren->Device->CreateBuffer(&desc, buffer ? &sr : NULL, &D3DBuffer.GetRawRef());
- if (SUCCEEDED(hr))
- {
- Use = use;
- Size = desc.ByteWidth;
- return 1;
- }
- return 0;
-}
-
-void* Buffer::Map(size_t start, size_t size, int flags)
-{
- OVR_UNUSED(size);
-
- D3D1x_(MAP) mapFlags = D3D1x_(MAP_WRITE);
- if (flags & Map_Discard)
- mapFlags = D3D1x_(MAP_WRITE_DISCARD);
- if (flags & Map_Unsynchronized)
- mapFlags = D3D1x_(MAP_WRITE_NO_OVERWRITE);
-
- void* map = 0;
- if (SUCCEEDED(D3DBuffer->Map(mapFlags, 0, &map)))
- return ((char*)map) + start;
- return NULL;
-}
-
-bool Buffer::Unmap(void *m)
-{
- OVR_UNUSED(m);
-
- D3DBuffer->Unmap();
- return true;
-}
-
-
-//-------------------------------------------------------------------------------------
-// Shaders
-
-template<> bool Shader<RenderTiny::Shader_Vertex, ID3D10VertexShader>::Load(void* shader, size_t size)
-{
- return SUCCEEDED(Ren->Device->CreateVertexShader(shader, size, &D3DShader));
-}
-template<> bool Shader<RenderTiny::Shader_Pixel, ID3D10PixelShader>::Load(void* shader, size_t size)
-{
- return SUCCEEDED(Ren->Device->CreatePixelShader(shader, size, &D3DShader));
-}
-
-template<> void Shader<RenderTiny::Shader_Vertex, ID3D10VertexShader>::Set(PrimitiveType) const
-{
- Ren->Context->VSSetShader(D3DShader);
-}
-template<> void Shader<RenderTiny::Shader_Pixel, ID3D10PixelShader>::Set(PrimitiveType) const
-{
- Ren->Context->PSSetShader(D3DShader);
-}
-
-template<> void Shader<RenderTiny::Shader_Vertex, ID3D1xVertexShader>::SetUniformBuffer(RenderTiny::Buffer* buffer, int i)
-{
- Ren->Context->VSSetConstantBuffers(i, 1, &((Buffer*)buffer)->D3DBuffer.GetRawRef());
-}
-template<> void Shader<RenderTiny::Shader_Pixel, ID3D1xPixelShader>::SetUniformBuffer(RenderTiny::Buffer* buffer, int i)
-{
- Ren->Context->PSSetConstantBuffers(i, 1, &((Buffer*)buffer)->D3DBuffer.GetRawRef());
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** Shader Base
-
-ShaderBase::ShaderBase(RenderDevice* r, ShaderStage stage)
- : RenderTiny::Shader(stage), Ren(r), UniformData(0)
-{
-}
-ShaderBase::~ShaderBase()
-{
- if (UniformData)
- OVR_FREE(UniformData);
-}
-
-bool ShaderBase::SetUniform(const char* name, int n, const float* v)
-{
- for(unsigned i = 0; i < UniformInfo.GetSize(); i++)
- {
- if (!strcmp(UniformInfo[i].Name.ToCStr(), name))
- {
- memcpy(UniformData + UniformInfo[i].Offset, v, n * sizeof(float));
- return 1;
- }
- }
- return 0;
-}
-
-void ShaderBase::InitUniforms(ID3D10Blob* s)
-{
- ID3D10ShaderReflection* ref = NULL;
- D3D10ReflectShader(s->GetBufferPointer(), s->GetBufferSize(), &ref);
- ID3D10ShaderReflectionConstantBuffer* buf = ref->GetConstantBufferByIndex(0);
- D3D10_SHADER_BUFFER_DESC bufd;
- if (FAILED(buf->GetDesc(&bufd)))
- {
- UniformsSize = 0;
- if (UniformData)
- {
- OVR_FREE(UniformData);
- UniformData = 0;
- }
- return;
- }
-
- for(unsigned i = 0; i < bufd.Variables; i++)
- {
- ID3D10ShaderReflectionVariable* var = buf->GetVariableByIndex(i);
- if (var)
- {
- D3D10_SHADER_VARIABLE_DESC vd;
- if (SUCCEEDED(var->GetDesc(&vd)))
- {
- Uniform u;
- u.Name = vd.Name;
- u.Offset = vd.StartOffset;
- u.Size = vd.Size;
- UniformInfo.PushBack(u);
- }
- }
- }
-
- UniformsSize = bufd.Size;
- UniformData = (unsigned char*)OVR_ALLOC(bufd.Size);
-}
-
-void ShaderBase::UpdateBuffer(Buffer* buf)
-{
- if (UniformsSize)
- {
- buf->Data(Buffer_Uniform, UniformData, UniformsSize);
- }
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** Texture
-//
-Texture::Texture(RenderDevice* ren, int fmt, int w, int h)
- : Ren(ren), Tex(NULL), TexSv(NULL), TexRtv(NULL), TexDsv(NULL), Width(w), Height(h)
-{
- OVR_UNUSED(fmt);
- Sampler = Ren->GetSamplerState(0);
-}
-
-Texture::~Texture()
-{
-}
-
-void Texture::Set(int slot, RenderTiny::ShaderStage stage) const
-{
- Ren->SetTexture(stage, slot, this);
-}
-
-void Texture::SetSampleMode(int sm)
-{
- Sampler = Ren->GetSamplerState(sm);
-}
-
-
-
-//-------------------------------------------------------------------------------------
-// ***** Render Device
-
-RenderDevice::RenderDevice(const RendererParams& p, HWND window)
-{
- RECT rc;
- GetClientRect(window, &rc);
- UINT width = rc.right - rc.left;
- UINT height = rc.bottom - rc.top;
- WindowWidth = width;
- WindowHeight = height;
- Window = window;
- Params = p;
-
- HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&DXGIFactory.GetRawRef()));
- if (FAILED(hr))
- return;
-
- // Find the adapter & output (monitor) to use for fullscreen, based on the reported name of the HMD's monitor.
- if (Params.MonitorName.GetLength() > 0)
- {
- for(UINT AdapterIndex = 0; ; AdapterIndex++)
- {
- HRESULT hr = DXGIFactory->EnumAdapters(AdapterIndex, &Adapter.GetRawRef());
- if (hr == DXGI_ERROR_NOT_FOUND)
- break;
-
- DXGI_ADAPTER_DESC Desc;
- Adapter->GetDesc(&Desc);
-
- UpdateMonitorOutputs();
-
- if (FullscreenOutput)
- break;
- }
-
- if (!FullscreenOutput)
- Adapter = NULL;
- }
-
- if (!Adapter)
- {
- DXGIFactory->EnumAdapters(0, &Adapter.GetRawRef());
- }
-
- int flags = 0;
-
- hr = D3D10CreateDevice(Adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D1x_(SDK_VERSION),
- &Device.GetRawRef());
- Context = Device;
- Context->AddRef();
-
- if (FAILED(hr))
- return;
-
- if (!RecreateSwapChain())
- return;
-
- if (Params.Fullscreen)
- SwapChain->SetFullscreenState(1, FullscreenOutput);
-
- CurRenderTarget = NULL;
- for(int i = 0; i < Shader_Count; i++)
- {
- UniformBuffers[i] = *CreateBuffer();
- MaxTextureSet[i] = 0;
- }
-
- ID3D10Blob* vsData = CompileShader("vs_4_0", DirectVertexShaderSrc);
- VertexShaders[VShader_MV] = *new VertexShader(this, vsData);
- for(int i = 1; i < VShader_Count; i++)
- {
- VertexShaders[i] = *new VertexShader(this, CompileShader("vs_4_0", VShaderSrcs[i]));
- }
-
- for(int i = 0; i < FShader_Count; i++)
- {
- PixelShaders[i] = *new PixelShader(this, CompileShader("ps_4_0", FShaderSrcs[i]));
- }
-
- SPInt bufferSize = vsData->GetBufferSize();
- const void* buffer = vsData->GetBufferPointer();
- ID3D1xInputLayout** objRef = &ModelVertexIL.GetRawRef();
-
- HRESULT validate = Device->CreateInputLayout(ModelVertexDesc, sizeof(ModelVertexDesc)/sizeof(D3D1x_(INPUT_ELEMENT_DESC)),
- buffer, bufferSize, objRef);
- OVR_UNUSED(validate);
-
- Ptr<ShaderSet> gouraudShaders = *new ShaderSet();
- gouraudShaders->SetShader(VertexShaders[VShader_MVP]);
- gouraudShaders->SetShader(PixelShaders[FShader_Gouraud]);
- DefaultFill = *new ShaderFill(gouraudShaders);
-
- D3D1x_(BLEND_DESC) bm;
- memset(&bm, 0, sizeof(bm));
- bm.BlendEnable[0] = true;
- bm.BlendOp = bm.BlendOpAlpha = D3D1x_(BLEND_OP_ADD);
- bm.SrcBlend = bm.SrcBlendAlpha = D3D1x_(BLEND_SRC_ALPHA);
- bm.DestBlend = bm.DestBlendAlpha = D3D1x_(BLEND_INV_SRC_ALPHA);
- bm.RenderTargetWriteMask[0] = D3D1x_(COLOR_WRITE_ENABLE_ALL);
- Device->CreateBlendState(&bm, &BlendState.GetRawRef());
-
- D3D1x_(RASTERIZER_DESC) rs;
- memset(&rs, 0, sizeof(rs));
- rs.AntialiasedLineEnable = true;
- rs.CullMode = D3D1x_(CULL_BACK);
- rs.DepthClipEnable = true;
- rs.FillMode = D3D1x_(FILL_SOLID);
- Device->CreateRasterizerState(&rs, &Rasterizer.GetRawRef());
-
- QuadVertexBuffer = *CreateBuffer();
- const RenderTiny::Vertex QuadVertices[] =
- { Vertex(Vector3f(0, 1, 0)), Vertex(Vector3f(1, 1, 0)),
- Vertex(Vector3f(0, 0, 0)), Vertex(Vector3f(1, 0, 0)) };
- QuadVertexBuffer->Data(Buffer_Vertex, QuadVertices, sizeof(QuadVertices));
-
- SetDepthMode(0, 0);
-}
-
-RenderDevice::~RenderDevice()
-{
- if (SwapChain && Params.Fullscreen)
- {
- SwapChain->SetFullscreenState(false, NULL);
- }
-}
-
-
-// Implement static initializer function to create this class.
-RenderTiny::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd)
-{
- return new RenderDevice(rp, (HWND)oswnd);
-}
-
-
-// Fallback monitor enumeration in case newly plugged in monitor wasn't detected.
-// Added originally for the FactoryTest app.
-// New Outputs don't seem to be detected unless adapter is re-created, but that would also
-// require us to re-initialize D3D10 (recreating objects, etc). This bypasses that for "fake"
-// fullscreen modes.
-BOOL CALLBACK MonitorEnumFunc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
-{
- RenderDevice* renderer = (RenderDevice*)dwData;
-
- MONITORINFOEX monitor;
- monitor.cbSize = sizeof(monitor);
-
- if (::GetMonitorInfo(hMonitor, &monitor) && monitor.szDevice[0])
- {
- DISPLAY_DEVICE dispDev;
- memset(&dispDev, 0, sizeof(dispDev));
- dispDev.cb = sizeof(dispDev);
-
- if (::EnumDisplayDevices(monitor.szDevice, 0, &dispDev, 0))
- {
- if (strstr(String(dispDev.DeviceName).ToCStr(), renderer->GetParams().MonitorName.ToCStr()))
- {
- renderer->FSDesktopX = monitor.rcMonitor.left;
- renderer->FSDesktopY = monitor.rcMonitor.top;
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-
-void RenderDevice::UpdateMonitorOutputs()
-{
- HRESULT hr;
-
- bool deviceNameFound = false;
-
- for(UINT OutputIndex = 0; ; OutputIndex++)
- {
- Ptr<IDXGIOutput> Output;
- hr = Adapter->EnumOutputs(OutputIndex, &Output.GetRawRef());
- if (hr == DXGI_ERROR_NOT_FOUND)
- {
- break;
- }
-
- DXGI_OUTPUT_DESC OutDesc;
- Output->GetDesc(&OutDesc);
-
- MONITORINFOEX monitor;
- monitor.cbSize = sizeof(monitor);
- if (::GetMonitorInfo(OutDesc.Monitor, &monitor) && monitor.szDevice[0])
- {
- DISPLAY_DEVICE dispDev;
- memset(&dispDev, 0, sizeof(dispDev));
- dispDev.cb = sizeof(dispDev);
-
- if (::EnumDisplayDevices(monitor.szDevice, 0, &dispDev, 0))
- {
- if (strstr(String(dispDev.DeviceName).ToCStr(), Params.MonitorName.ToCStr()))
- {
- deviceNameFound = true;
- FullscreenOutput = Output;
- FSDesktopX = monitor.rcMonitor.left;
- FSDesktopY = monitor.rcMonitor.top;
- break;
- }
- }
- }
- }
-
- if (!deviceNameFound && !Params.MonitorName.IsEmpty())
- {
- EnumDisplayMonitors(0, 0, MonitorEnumFunc, (LPARAM)this);
- }
-}
-
-bool RenderDevice::RecreateSwapChain()
-{
- DXGI_SWAP_CHAIN_DESC scDesc;
- memset(&scDesc, 0, sizeof(scDesc));
- scDesc.BufferCount = 1;
- scDesc.BufferDesc.Width = WindowWidth;
- scDesc.BufferDesc.Height = WindowHeight;
- scDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- scDesc.BufferDesc.RefreshRate.Numerator = 60;
- scDesc.BufferDesc.RefreshRate.Denominator = 1;
- scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- scDesc.OutputWindow = Window;
- scDesc.SampleDesc.Count = Params.Multisample;
- scDesc.SampleDesc.Quality = 0;
- scDesc.Windowed = (Params.Fullscreen != Display_Fullscreen);
- scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
-
- if (SwapChain)
- {
- SwapChain->SetFullscreenState(FALSE, NULL);
- SwapChain->Release();
- SwapChain = NULL;
- }
-
- Ptr<IDXGISwapChain> newSC;
- if (FAILED(DXGIFactory->CreateSwapChain(Device, &scDesc, &newSC.GetRawRef())))
- return false;
- SwapChain = newSC;
-
- BackBuffer = NULL;
- BackBufferRT = NULL;
- HRESULT hr = SwapChain->GetBuffer(0, __uuidof(ID3D1xTexture2D), (void**)&BackBuffer.GetRawRef());
- if (FAILED(hr))
- return false;
-
- hr = Device->CreateRenderTargetView(BackBuffer, NULL, &BackBufferRT.GetRawRef());
- if (FAILED(hr))
- return false;
-
- Texture* depthBuffer = GetDepthBuffer(WindowWidth, WindowHeight, Params.Multisample);
- CurDepthBuffer = depthBuffer;
- if (CurRenderTarget == NULL)
- {
- Context->OMSetRenderTargets(1, &BackBufferRT.GetRawRef(), depthBuffer->TexDsv);
- }
- return true;
-}
-
-bool RenderDevice::SetParams(const RendererParams& newParams)
-{
- String oldMonitor = Params.MonitorName;
-
- Params = newParams;
- if (newParams.MonitorName != oldMonitor)
- {
- UpdateMonitorOutputs();
- }
-
- // Cause this to be recreated with the new multisample mode.
- pSceneColorTex = NULL;
- return RecreateSwapChain();
-}
-
-
-bool RenderDevice::SetFullscreen(DisplayMode fullscreen)
-{
- if (fullscreen == Params.Fullscreen)
- return true;
-
- HRESULT hr = SwapChain->SetFullscreenState(fullscreen, fullscreen ? FullscreenOutput : NULL);
- if (FAILED(hr))
- {
- return false;
- }
-
- Params.Fullscreen = fullscreen;
- return true;
-}
-
-void RenderDevice::SetRealViewport(const Viewport& vp)
-{
- D3DViewport.Width = vp.w;
- D3DViewport.Height = vp.h;
- D3DViewport.MinDepth = 0;
- D3DViewport.MaxDepth = 1;
- D3DViewport.TopLeftX = vp.x;
- D3DViewport.TopLeftY = vp.y;
- Context->RSSetViewports(1, &D3DViewport);
-}
-
-static int GetDepthStateIndex(bool enable, bool write, RenderDevice::CompareFunc func)
-{
- if (!enable)
- return 0;
- return 1 + int(func) * 2 + write;
-}
-
-void RenderDevice::SetDepthMode(bool enable, bool write, CompareFunc func)
-{
- int index = GetDepthStateIndex(enable, write, func);
- if (DepthStates[index])
- {
- CurDepthState = DepthStates[index];
- Context->OMSetDepthStencilState(DepthStates[index], 0);
- return;
- }
-
- D3D1x_(DEPTH_STENCIL_DESC) dss;
- memset(&dss, 0, sizeof(dss));
- dss.DepthEnable = enable;
- switch(func)
- {
- case Compare_Always: dss.DepthFunc = D3D1x_(COMPARISON_ALWAYS); break;
- case Compare_Less: dss.DepthFunc = D3D1x_(COMPARISON_LESS); break;
- case Compare_Greater: dss.DepthFunc = D3D1x_(COMPARISON_GREATER); break;
- default:
- assert(0);
- }
- dss.DepthWriteMask = write ? D3D1x_(DEPTH_WRITE_MASK_ALL) : D3D1x_(DEPTH_WRITE_MASK_ZERO);
- Device->CreateDepthStencilState(&dss, &DepthStates[index].GetRawRef());
- Context->OMSetDepthStencilState(DepthStates[index], 0);
- CurDepthState = DepthStates[index];
-}
-
-Texture* RenderDevice::GetDepthBuffer(int w, int h, int ms)
-{
- for(unsigned i = 0; i < DepthBuffers.GetSize(); i++)
- {
- if (w == DepthBuffers[i]->Width && h == DepthBuffers[i]->Height &&
- ms == DepthBuffers[i]->Samples)
- return DepthBuffers[i];
- }
-
- Ptr<Texture> newDepth = *CreateTexture(Texture_Depth | Texture_RenderTarget | ms, w, h, NULL);
- if (newDepth == NULL)
- {
- OVR_DEBUG_LOG(("Failed to get depth buffer."));
- return NULL;
- }
-
- DepthBuffers.PushBack(newDepth);
- return newDepth.GetPtr();
-}
-
-void RenderDevice::Clear(float r, float g, float b, float a, float depth)
-{
- const float color[] = {r, g, b, a};
-
- // Needed for each eye to do its own clear, since ClearRenderTargetView doesn't honor viewport.
-
- // Save state that is affected by clearing this way
- ID3D1xDepthStencilState* oldDepthState = CurDepthState;
- StandardUniformData clearUniforms;
-
- SetDepthMode(true, true, Compare_Always);
-
- Context->IASetInputLayout(ModelVertexIL);
- Context->GSSetShader(NULL);
-
- ID3D1xShaderResourceView* sv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- if (MaxTextureSet[Shader_Fragment])
- {
- Context->PSSetShaderResources(0, MaxTextureSet[Shader_Fragment], sv);
- }
-
- ID3D1xBuffer* vertexBuffer = QuadVertexBuffer->GetBuffer();
- UINT vertexStride = sizeof(Vertex);
- UINT vertexOffset = 0;
- Context->IASetVertexBuffers(0, 1, &vertexBuffer, &vertexStride, &vertexOffset);
-
- clearUniforms.View = Matrix4f(2, 0, 0, 0,
- 0, 2, 0, 0,
- 0, 0, 0, 0,
- -1, -1, depth, 1);
- UniformBuffers[Shader_Vertex]->Data(Buffer_Uniform, &clearUniforms, sizeof(clearUniforms));
-
- ID3D1xBuffer* vertexConstants = UniformBuffers[Shader_Vertex]->GetBuffer();
- Context->VSSetConstantBuffers(0, 1, &vertexConstants);
- Context->IASetPrimitiveTopology(D3D1x_(PRIMITIVE_TOPOLOGY_TRIANGLESTRIP));
- VertexShaders[VShader_MV]->Set(Prim_TriangleStrip);
- PixelShaders[FShader_Solid]->Set(Prim_TriangleStrip);
-
- UniformBuffers[Shader_Pixel]->Data(Buffer_Uniform, color, sizeof(color));
- PixelShaders[FShader_Solid]->SetUniformBuffer(UniformBuffers[Shader_Pixel]);
-
- // Clear Viewport
- Context->OMSetBlendState(NULL, NULL, 0xffffffff);
- Context->Draw(4, 0);
-
- // reset
- CurDepthState = oldDepthState;
- Context->OMSetDepthStencilState(CurDepthState, 0);
-}
-
-// Buffers
-
-Buffer* RenderDevice::CreateBuffer()
-{
- return new Buffer(this);
-}
-
-
-ID3D10Blob* RenderDevice::CompileShader(const char* profile, const char* src, const char* mainName)
-{
- ID3D10Blob* shader;
- ID3D10Blob* errors;
- HRESULT hr = D3DCompile(src, strlen(src), NULL, NULL, NULL, mainName, profile,
- 0, 0, &shader, &errors);
- if (FAILED(hr))
- {
- OVR_DEBUG_LOG(("Compiling D3D shader for %s failed\n%s\n\n%s",
- profile, src, errors->GetBufferPointer()));
- OutputDebugStringA((char*)errors->GetBufferPointer());
- return NULL;
- }
- if (errors)
- {
- errors->Release();
- }
- return shader;
-}
-
-void RenderDevice::SetCommonUniformBuffer(int i, RenderTiny::Buffer* buffer)
-{
- CommonUniforms[i] = (Buffer*)buffer;
-
- Context->PSSetConstantBuffers(1, 1, &CommonUniforms[1]->D3DBuffer.GetRawRef());
- Context->VSSetConstantBuffers(1, 1, &CommonUniforms[1]->D3DBuffer.GetRawRef());
-}
-
-RenderTiny::Shader *RenderDevice::LoadBuiltinShader(ShaderStage stage, int shader)
-{
- switch(stage)
- {
- case Shader_Vertex:
- return VertexShaders[shader];
- case Shader_Pixel:
- return PixelShaders[shader];
- default:
- return NULL;
- }
-}
-
-
-ID3D1xSamplerState* RenderDevice::GetSamplerState(int sm)
-{
- if (SamplerStates[sm])
- return SamplerStates[sm];
-
- D3D1x_(SAMPLER_DESC) ss;
- memset(&ss, 0, sizeof(ss));
- if (sm & Sample_Clamp)
- ss.AddressU = ss.AddressV = ss.AddressW = D3D1x_(TEXTURE_ADDRESS_CLAMP);
- else if (sm & Sample_ClampBorder)
- ss.AddressU = ss.AddressV = ss.AddressW = D3D1x_(TEXTURE_ADDRESS_BORDER);
- else
- ss.AddressU = ss.AddressV = ss.AddressW = D3D1x_(TEXTURE_ADDRESS_WRAP);
-
- if (sm & Sample_Nearest)
- {
- ss.Filter = D3D1x_(FILTER_MIN_MAG_MIP_POINT);
- }
- else if (sm & Sample_Anisotropic)
- {
- ss.Filter = D3D1x_(FILTER_ANISOTROPIC);
- ss.MaxAnisotropy = 8;
- }
- else
- {
- ss.Filter = D3D1x_(FILTER_MIN_MAG_MIP_LINEAR);
- }
- ss.MaxLOD = 15;
- Device->CreateSamplerState(&ss, &SamplerStates[sm].GetRawRef());
- return SamplerStates[sm];
-}
-
-
-void RenderDevice::SetTexture(RenderTiny::ShaderStage stage, int slot, const Texture* t)
-{
- if (MaxTextureSet[stage] <= slot)
- MaxTextureSet[stage] = slot + 1;
-
- ID3D1xShaderResourceView* sv = t ? t->TexSv : NULL;
- switch(stage)
- {
- case Shader_Fragment:
- Context->PSSetShaderResources(slot, 1, &sv);
- if (t)
- {
- Context->PSSetSamplers(slot, 1, &t->Sampler.GetRawRef());
- }
- break;
-
- case Shader_Vertex:
- Context->VSSetShaderResources(slot, 1, &sv);
- break;
- }
-}
-
-Texture* RenderDevice::CreateTexture(int format, int width, int height, const void* data, int mipcount)
-{
- OVR_UNUSED(mipcount);
-
- DXGI_FORMAT d3dformat;
- int bpp;
- switch(format & Texture_TypeMask)
- {
- case Texture_RGBA:
- bpp = 4;
- d3dformat = DXGI_FORMAT_R8G8B8A8_UNORM;
- break;
- case Texture_Depth:
- bpp = 0;
- d3dformat = DXGI_FORMAT_D32_FLOAT;
- break;
- default:
- return NULL;
- }
-
- int samples = (format & Texture_SamplesMask);
- if (samples < 1)
- {
- samples = 1;
- }
-
- Texture* NewTex = new Texture(this, format, width, height);
- NewTex->Samples = samples;
-
- D3D1x_(TEXTURE2D_DESC) dsDesc;
- dsDesc.Width = width;
- dsDesc.Height = height;
- dsDesc.MipLevels = (format == (Texture_RGBA | Texture_GenMipmaps) && data) ? GetNumMipLevels(width, height) : 1;
- dsDesc.ArraySize = 1;
- dsDesc.Format = d3dformat;
- dsDesc.SampleDesc.Count = samples;
- dsDesc.SampleDesc.Quality = 0;
- dsDesc.Usage = D3D1x_(USAGE_DEFAULT);
- dsDesc.BindFlags = D3D1x_(BIND_SHADER_RESOURCE);
- dsDesc.CPUAccessFlags = 0;
- dsDesc.MiscFlags = 0;
-
- if (format & Texture_RenderTarget)
- {
- if ((format & Texture_TypeMask) == Texture_Depth)
- { // We don't use depth textures, and creating them in d3d10 requires different options.
- dsDesc.BindFlags = D3D1x_(BIND_DEPTH_STENCIL);
- }
- else
- {
- dsDesc.BindFlags |= D3D1x_(BIND_RENDER_TARGET);
- }
- }
-
- HRESULT hr = Device->CreateTexture2D(&dsDesc, NULL, &NewTex->Tex.GetRawRef());
- if (FAILED(hr))
- {
- OVR_DEBUG_LOG_TEXT(("Failed to create 2D D3D texture."));
- NewTex->Release();
- return NULL;
- }
- if (dsDesc.BindFlags & D3D1x_(BIND_SHADER_RESOURCE))
- {
- Device->CreateShaderResourceView(NewTex->Tex, NULL, &NewTex->TexSv.GetRawRef());
- }
-
- if (data)
- {
- Context->UpdateSubresource(NewTex->Tex, 0, NULL, data, width * bpp, width * height * bpp);
- if (format == (Texture_RGBA | Texture_GenMipmaps))
- {
- int srcw = width, srch = height;
- int level = 0;
- UByte* mipmaps = NULL;
- do
- {
- level++;
- int mipw = srcw >> 1;
- if (mipw < 1)
- {
- mipw = 1;
- }
- int miph = srch >> 1;
- if (miph < 1)
- {
- miph = 1;
- }
- if (mipmaps == NULL)
- {
- mipmaps = (UByte*)OVR_ALLOC(mipw * miph * 4);
- }
- FilterRgba2x2(level == 1 ? (const UByte*)data : mipmaps, srcw, srch, mipmaps);
- Context->UpdateSubresource(NewTex->Tex, level, NULL, mipmaps, mipw * bpp, miph * bpp);
- srcw = mipw;
- srch = miph;
- }
- while(srcw > 1 || srch > 1);
-
- if (mipmaps != NULL)
- {
- OVR_FREE(mipmaps);
- }
- }
- }
-
- if (format & Texture_RenderTarget)
- {
- if ((format & Texture_TypeMask) == Texture_Depth)
- {
- Device->CreateDepthStencilView(NewTex->Tex, NULL, &NewTex->TexDsv.GetRawRef());
- }
- else
- {
- Device->CreateRenderTargetView(NewTex->Tex, NULL, &NewTex->TexRtv.GetRawRef());
- }
- }
-
- return NewTex;
-}
-
-
-// Rendering
-
-void RenderDevice::BeginRendering()
-{
- Context->RSSetState(Rasterizer);
-}
-
-void RenderDevice::SetRenderTarget(RenderTiny::Texture* colorTex,
- RenderTiny::Texture* depth, RenderTiny::Texture* stencil)
-{
- OVR_UNUSED(stencil);
-
- CurRenderTarget = (Texture*)colorTex;
- if (colorTex == NULL)
- {
- Texture* newDepthBuffer = GetDepthBuffer(WindowWidth, WindowHeight, Params.Multisample);
- if (newDepthBuffer == NULL)
- {
- OVR_DEBUG_LOG(("New depth buffer creation failed."));
- }
- if (newDepthBuffer != NULL)
- {
- CurDepthBuffer = GetDepthBuffer(WindowWidth, WindowHeight, Params.Multisample);
- Context->OMSetRenderTargets(1, &BackBufferRT.GetRawRef(), CurDepthBuffer->TexDsv);
- }
- return;
- }
- if (depth == NULL)
- {
- depth = GetDepthBuffer(colorTex->GetWidth(), colorTex->GetHeight(), CurRenderTarget->Samples);
- }
-
- ID3D1xShaderResourceView* sv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
- if (MaxTextureSet[Shader_Fragment])
- {
- Context->PSSetShaderResources(0, MaxTextureSet[Shader_Fragment], sv);
- }
- memset(MaxTextureSet, 0, sizeof(MaxTextureSet));
-
- CurDepthBuffer = (Texture*)depth;
- Context->OMSetRenderTargets(1, &((Texture*)colorTex)->TexRtv.GetRawRef(), ((Texture*)depth)->TexDsv);
-}
-
-
-void RenderDevice::SetWorldUniforms(const Matrix4f& proj)
-{
- StdUniforms.Proj = proj.Transposed();
- // Shader constant buffers cannot be partially updated.
-}
-
-
-void RenderDevice::Render(const Matrix4f& matrix, Model* model)
-{
- // Store data in buffers if not already
- if (!model->VertexBuffer)
- {
- Ptr<Buffer> vb = *CreateBuffer();
- vb->Data(Buffer_Vertex, &model->Vertices[0], model->Vertices.GetSize() * sizeof(Vertex));
- model->VertexBuffer = vb;
- }
- if (!model->IndexBuffer)
- {
- Ptr<Buffer> ib = *CreateBuffer();
- ib->Data(Buffer_Index, &model->Indices[0], model->Indices.GetSize() * 2);
- model->IndexBuffer = ib;
- }
-
- Render(model->Fill ? model->Fill : DefaultFill,
- model->VertexBuffer, model->IndexBuffer,
- matrix, 0, (unsigned)model->Indices.GetSize(), model->GetPrimType());
-}
-
-void RenderDevice::Render(const ShaderFill* fill, RenderTiny::Buffer* vertices, RenderTiny::Buffer* indices,
- const Matrix4f& matrix, int offset, int count, PrimitiveType rprim)
-{
- Context->IASetInputLayout(ModelVertexIL);
- if (indices)
- {
- Context->IASetIndexBuffer(((Buffer*)indices)->GetBuffer(), DXGI_FORMAT_R16_UINT, 0);
- }
-
- ID3D1xBuffer* vertexBuffer = ((Buffer*)vertices)->GetBuffer();
- UINT vertexStride = sizeof(Vertex);
- UINT vertexOffset = offset;
- Context->IASetVertexBuffers(0, 1, &vertexBuffer, &vertexStride, &vertexOffset);
-
- ShaderSet* shaders = ((ShaderFill*)fill)->GetShaders();
-
- ShaderBase* vshader = ((ShaderBase*)shaders->GetShader(Shader_Vertex));
- unsigned char* vertexData = vshader->UniformData;
- if (vertexData)
- {
- StandardUniformData* stdUniforms = (StandardUniformData*) vertexData;
- stdUniforms->View = matrix.Transposed();
- stdUniforms->Proj = StdUniforms.Proj;
- UniformBuffers[Shader_Vertex]->Data(Buffer_Uniform, vertexData, vshader->UniformsSize);
- vshader->SetUniformBuffer(UniformBuffers[Shader_Vertex]);
- }
-
- for(int i = Shader_Vertex + 1; i < Shader_Count; i++)
- if (shaders->GetShader(i))
- {
- ((ShaderBase*)shaders->GetShader(i))->UpdateBuffer(UniformBuffers[i]);
- ((ShaderBase*)shaders->GetShader(i))->SetUniformBuffer(UniformBuffers[i]);
- }
-
- D3D1x_(PRIMITIVE_TOPOLOGY) prim;
- switch(rprim)
- {
- case Prim_Triangles:
- prim = D3D1x_(PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- break;
- case Prim_Lines:
- prim = D3D1x_(PRIMITIVE_TOPOLOGY_LINELIST);
- break;
- case Prim_TriangleStrip:
- prim = D3D1x_(PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
- break;
- default:
- assert(0);
- return;
- }
- Context->IASetPrimitiveTopology(prim);
-
- fill->Set(rprim);
-
- if (indices)
- {
- Context->DrawIndexed(count, 0, 0);
- }
- else
- {
- Context->Draw(count, 0);
- }
-}
-
-
-void RenderDevice::Present()
-{
- SwapChain->Present(0, 0);
-}
-
-void RenderDevice::ForceFlushGPU()
-{
- D3D1x_QUERY_DESC queryDesc = { D3D1x_(QUERY_EVENT), 0 };
- Ptr<ID3D1xQuery> query;
- BOOL done = FALSE;
-
- if (Device->CreateQuery(&queryDesc, &query.GetRawRef()) == S_OK)
- {
- // Begin() not used for EVENT query.
- query->End();
- // GetData will returns S_OK for both done == TRUE or FALSE.
- // Exit on failure to avoid infinite loop.
- do { }
- while(!done && !FAILED(query->GetData(&done, sizeof(BOOL), 0)));
- }
-}
-
-}}}
-
+/************************************************************************************ + +Filename : RenderTiny_D3D1x.cpp +Content : RenderDevice implementation for D3DX10/11. +Created : September 10, 2012 +Authors : Andrew Reisse + +Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include "Kernel/OVR_Log.h" +#include "Kernel/OVR_Std.h" + +#include "RenderTiny_D3D1X_Device.h" + +#include <d3dcompiler.h> + +namespace OVR { namespace RenderTiny { namespace D3D10 { + + +//------------------------------------------------------------------------------------- +// Vertex format +static D3D1x_(INPUT_ELEMENT_DESC) ModelVertexDesc[] = +{ + {"Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, Pos), D3D1x_(INPUT_PER_VERTEX_DATA), 0}, + {"Color", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(Vertex, C), D3D1x_(INPUT_PER_VERTEX_DATA), 0}, + {"TexCoord", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(Vertex, U), D3D1x_(INPUT_PER_VERTEX_DATA), 0}, + {"Normal", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(Vertex, Norm), D3D1x_(INPUT_PER_VERTEX_DATA), 0}, +}; + +// These shaders are used to render the world, including lit vertex-colored and textured geometry. + +// Used for world geometry; has projection matrix. +static const char* StdVertexShaderSrc = + "float4x4 Proj;\n" + "float4x4 View;\n" + "struct Varyings\n" + "{\n" + " float4 Position : SV_Position;\n" + " float4 Color : COLOR0;\n" + " float2 TexCoord : TEXCOORD0;\n" + " float3 Normal : NORMAL;\n" + " float3 VPos : TEXCOORD4;\n" + "};\n" + "void main(in float4 Position : POSITION, in float4 Color : COLOR0, in float2 TexCoord : TEXCOORD0," + " in float3 Normal : NORMAL,\n" + " out Varyings ov)\n" + "{\n" + " ov.Position = mul(Proj, mul(View, Position));\n" + " ov.Normal = mul(View, Normal);\n" + " ov.VPos = mul(View, Position);\n" + " ov.TexCoord = TexCoord;\n" + " ov.Color = Color;\n" + "}\n"; + +// Used for text/clearing; no projection. +static const char* DirectVertexShaderSrc = + "float4x4 View : register(c4);\n" + "void main(in float4 Position : POSITION, in float4 Color : COLOR0,\n" + " in float2 TexCoord : TEXCOORD0, in float3 Normal : NORMAL,\n" + " out float4 oPosition : SV_Position, out float4 oColor : COLOR,\n" + " out float2 oTexCoord : TEXCOORD0," + " out float3 oNormal : NORMAL)\n" + "{\n" + " oPosition = mul(View, Position);\n" + " oTexCoord = TexCoord;\n" + " oColor = Color;\n" + " oNormal = mul(View, Normal);\n" + "}\n"; + +static const char* SolidPixelShaderSrc = + "float4 Color;\n" + "struct Varyings\n" + "{\n" + " float4 Position : SV_Position;\n" + " float4 Color : COLOR0;\n" + " float2 TexCoord : TEXCOORD0;\n" + "};\n" + "float4 main(in Varyings ov) : SV_Target\n" + "{\n" + " return Color;\n" + "}\n"; + +static const char* GouraudPixelShaderSrc = + "struct Varyings\n" + "{\n" + " float4 Position : SV_Position;\n" + " float4 Color : COLOR0;\n" + " float2 TexCoord : TEXCOORD0;\n" + "};\n" + "float4 main(in Varyings ov) : SV_Target\n" + "{\n" + " return ov.Color;\n" + "}\n"; + +static const char* TexturePixelShaderSrc = + "Texture2D Texture : register(t0);\n" + "SamplerState Linear : register(s0);\n" + "struct Varyings\n" + "{\n" + " float4 Position : SV_Position;\n" + " float4 Color : COLOR0;\n" + " float2 TexCoord : TEXCOORD0;\n" + "};\n" + "float4 main(in Varyings ov) : SV_Target\n" + "{\n" + " float4 color2 = ov.Color * Texture.Sample(Linear, ov.TexCoord);\n" + " if (color2.a <= 0.4)\n" + " discard;\n" + " return color2;\n" + "}\n"; + + +#define LIGHTING_COMMON \ + "cbuffer Lighting : register(b1)\n" \ + "{\n" \ + " float3 Ambient;\n" \ + " float3 LightPos[8];\n" \ + " float4 LightColor[8];\n" \ + " float LightCount;\n" \ + "};\n" \ + "struct Varyings\n" \ + "{\n" \ + " float4 Position : SV_Position;\n" \ + " float4 Color : COLOR0;\n" \ + " float2 TexCoord : TEXCOORD0;\n" \ + " float3 Normal : NORMAL;\n" \ + " float3 VPos : TEXCOORD4;\n" \ + "};\n" \ + "float4 DoLight(Varyings v)\n" \ + "{\n" \ + " float3 norm = normalize(v.Normal);\n" \ + " float3 light = Ambient;\n" \ + " for (uint i = 0; i < LightCount; i++)\n"\ + " {\n" \ + " float3 ltp = (LightPos[i] - v.VPos);\n" \ + " float ldist = dot(ltp,ltp);\n" \ + " ltp = normalize(ltp);\n" \ + " light += saturate(LightColor[i] * v.Color.rgb * dot(norm, ltp) / sqrt(ldist));\n"\ + " }\n" \ + " return float4(light, v.Color.a);\n" \ + "}\n" + +static const char* LitSolidPixelShaderSrc = + LIGHTING_COMMON + "float4 main(in Varyings ov) : SV_Target\n" + "{\n" + " return DoLight(ov) * ov.Color;\n" + "}\n"; + +static const char* LitTexturePixelShaderSrc = + "Texture2D Texture : register(t0);\n" + "SamplerState Linear : register(s0);\n" + LIGHTING_COMMON + "float4 main(in Varyings ov) : SV_Target\n" + "{\n" + " return DoLight(ov) * Texture.Sample(Linear, ov.TexCoord);\n" + "}\n"; + + +//------------------------------------------------------------------------------------- +// ***** Distortion Post-process Shaders + +static const char* PostProcessVertexShaderSrc = + "float4x4 View : register(c4);\n" + "float4x4 Texm : register(c8);\n" + "void main(in float4 Position : POSITION, in float4 Color : COLOR0, in float2 TexCoord : TEXCOORD0,\n" + " out float4 oPosition : SV_Position, out float4 oColor : COLOR, out float2 oTexCoord : TEXCOORD0)\n" + "{\n" + " oPosition = mul(View, Position);\n" + " oTexCoord = mul(Texm, float4(TexCoord,0,1));\n" + " oColor = Color;\n" + "}\n"; + +// Shader with just lens distortion correction. +static const char* PostProcessPixelShaderSrc = + "Texture2D Texture : register(t0);\n" + "SamplerState Linear : register(s0);\n" + "float2 LensCenter;\n" + "float2 ScreenCenter;\n" + "float2 Scale;\n" + "float2 ScaleIn;\n" + "float4 HmdWarpParam;\n" + "\n" + + // Scales input texture coordinates for distortion. + // ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be + // larger due to aspect ratio. + "float2 HmdWarp(float2 in01)\n" + "{\n" + " float2 theta = (in01 - LensCenter) * ScaleIn;\n" // Scales to [-1, 1] + " float rSq = theta.x * theta.x + theta.y * theta.y;\n" + " float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + " + " HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);\n" + " return LensCenter + Scale * theta1;\n" + "}\n" + + "float4 main(in float4 oPosition : SV_Position, in float4 oColor : COLOR,\n" + " in float2 oTexCoord : TEXCOORD0) : SV_Target\n" + "{\n" + " float2 tc = HmdWarp(oTexCoord);\n" + " if (any(clamp(tc, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tc))\n" + " return 0;\n" + " return Texture.Sample(Linear, tc);\n" + "}\n"; + +// Shader with lens distortion and chromatic aberration correction. +static const char* PostProcessPixelShaderWithChromAbSrc = + "Texture2D Texture : register(t0);\n" + "SamplerState Linear : register(s0);\n" + "float2 LensCenter;\n" + "float2 ScreenCenter;\n" + "float2 Scale;\n" + "float2 ScaleIn;\n" + "float4 HmdWarpParam;\n" + "float4 ChromAbParam;\n" + "\n" + + // Scales input texture coordinates for distortion. + // ScaleIn maps texture coordinates to Scales to ([-1, 1]), although top/bottom will be + // larger due to aspect ratio. + "float4 main(in float4 oPosition : SV_Position, in float4 oColor : COLOR,\n" + " in float2 oTexCoord : TEXCOORD0) : SV_Target\n" + "{\n" + " float2 theta = (oTexCoord - LensCenter) * ScaleIn;\n" // Scales to [-1, 1] + " float rSq= theta.x * theta.x + theta.y * theta.y;\n" + " float2 theta1 = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + " + " HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq);\n" + " \n" + " // Detect whether blue texture coordinates are out of range since these will scaled out the furthest.\n" + " float2 thetaBlue = theta1 * (ChromAbParam.z + ChromAbParam.w * rSq);\n" + " float2 tcBlue = LensCenter + Scale * thetaBlue;\n" + " if (any(clamp(tcBlue, ScreenCenter-float2(0.25,0.5), ScreenCenter+float2(0.25, 0.5)) - tcBlue))\n" + " return 0;\n" + " \n" + " // Now do blue texture lookup.\n" + " float blue = Texture.Sample(Linear, tcBlue).b;\n" + " \n" + " // Do green lookup (no scaling).\n" + " float2 tcGreen = LensCenter + Scale * theta1;\n" + " float green = Texture.Sample(Linear, tcGreen).g;\n" + " \n" + " // Do red scale and lookup.\n" + " float2 thetaRed = theta1 * (ChromAbParam.x + ChromAbParam.y * rSq);\n" + " float2 tcRed = LensCenter + Scale * thetaRed;\n" + " float red = Texture.Sample(Linear, tcRed).r;\n" + " \n" + " return float4(red, green, blue, 1);\n" + "}\n"; + + +static const char* VShaderSrcs[VShader_Count] = +{ + DirectVertexShaderSrc, + StdVertexShaderSrc, + PostProcessVertexShaderSrc +}; +static const char* FShaderSrcs[FShader_Count] = +{ + SolidPixelShaderSrc, + GouraudPixelShaderSrc, + TexturePixelShaderSrc, + PostProcessPixelShaderSrc, + PostProcessPixelShaderWithChromAbSrc, + LitSolidPixelShaderSrc, + LitTexturePixelShaderSrc +}; + + +//------------------------------------------------------------------------------------- +// ***** Buffer + +Buffer::~Buffer() +{ +} + +bool Buffer::Data(int use, const void *buffer, size_t size) +{ + if (D3DBuffer && Size >= size) + { + if (Dynamic) + { + if (!buffer) + return true; + + void* v = Map(0, size, Map_Discard); + if (v) + { + memcpy(v, buffer, size); + Unmap(v); + return true; + } + } + else + { + Ren->Context->UpdateSubresource(D3DBuffer, 0, NULL, buffer, 0, 0); + return true; + } + } + if (D3DBuffer) + { + D3DBuffer = NULL; + Size = 0; + Use = 0; + Dynamic = 0; + } + + D3D1x_(BUFFER_DESC) desc; + memset(&desc, 0, sizeof(desc)); + if (use & Buffer_ReadOnly) + { + desc.Usage = D3D1x_(USAGE_IMMUTABLE); + desc.CPUAccessFlags = 0; + } + else + { + desc.Usage = D3D1x_(USAGE_DYNAMIC); + desc.CPUAccessFlags = D3D1x_(CPU_ACCESS_WRITE); + Dynamic = 1; + } + + switch(use & Buffer_TypeMask) + { + case Buffer_Vertex: desc.BindFlags = D3D1x_(BIND_VERTEX_BUFFER); break; + case Buffer_Index: desc.BindFlags = D3D1x_(BIND_INDEX_BUFFER); break; + case Buffer_Uniform: + desc.BindFlags = D3D1x_(BIND_CONSTANT_BUFFER); + size += ((size + 15) & ~15) - size; + break; + } + + desc.ByteWidth = (unsigned)size; + + D3D1x_(SUBRESOURCE_DATA) sr; + sr.pSysMem = buffer; + sr.SysMemPitch = 0; + sr.SysMemSlicePitch = 0; + + HRESULT hr = Ren->Device->CreateBuffer(&desc, buffer ? &sr : NULL, &D3DBuffer.GetRawRef()); + if (SUCCEEDED(hr)) + { + Use = use; + Size = desc.ByteWidth; + return 1; + } + return 0; +} + +void* Buffer::Map(size_t start, size_t size, int flags) +{ + OVR_UNUSED(size); + + D3D1x_(MAP) mapFlags = D3D1x_(MAP_WRITE); + if (flags & Map_Discard) + mapFlags = D3D1x_(MAP_WRITE_DISCARD); + if (flags & Map_Unsynchronized) + mapFlags = D3D1x_(MAP_WRITE_NO_OVERWRITE); + + void* map = 0; + if (SUCCEEDED(D3DBuffer->Map(mapFlags, 0, &map))) + return ((char*)map) + start; + return NULL; +} + +bool Buffer::Unmap(void *m) +{ + OVR_UNUSED(m); + + D3DBuffer->Unmap(); + return true; +} + + +//------------------------------------------------------------------------------------- +// Shaders + +template<> bool Shader<RenderTiny::Shader_Vertex, ID3D10VertexShader>::Load(void* shader, size_t size) +{ + return SUCCEEDED(Ren->Device->CreateVertexShader(shader, size, &D3DShader)); +} +template<> bool Shader<RenderTiny::Shader_Pixel, ID3D10PixelShader>::Load(void* shader, size_t size) +{ + return SUCCEEDED(Ren->Device->CreatePixelShader(shader, size, &D3DShader)); +} + +template<> void Shader<RenderTiny::Shader_Vertex, ID3D10VertexShader>::Set(PrimitiveType) const +{ + Ren->Context->VSSetShader(D3DShader); +} +template<> void Shader<RenderTiny::Shader_Pixel, ID3D10PixelShader>::Set(PrimitiveType) const +{ + Ren->Context->PSSetShader(D3DShader); +} + +template<> void Shader<RenderTiny::Shader_Vertex, ID3D1xVertexShader>::SetUniformBuffer(RenderTiny::Buffer* buffer, int i) +{ + Ren->Context->VSSetConstantBuffers(i, 1, &((Buffer*)buffer)->D3DBuffer.GetRawRef()); +} +template<> void Shader<RenderTiny::Shader_Pixel, ID3D1xPixelShader>::SetUniformBuffer(RenderTiny::Buffer* buffer, int i) +{ + Ren->Context->PSSetConstantBuffers(i, 1, &((Buffer*)buffer)->D3DBuffer.GetRawRef()); +} + + +//------------------------------------------------------------------------------------- +// ***** Shader Base + +ShaderBase::ShaderBase(RenderDevice* r, ShaderStage stage) + : RenderTiny::Shader(stage), Ren(r), UniformData(0) +{ +} +ShaderBase::~ShaderBase() +{ + if (UniformData) + OVR_FREE(UniformData); +} + +bool ShaderBase::SetUniform(const char* name, int n, const float* v) +{ + for(unsigned i = 0; i < UniformInfo.GetSize(); i++) + { + if (!strcmp(UniformInfo[i].Name.ToCStr(), name)) + { + memcpy(UniformData + UniformInfo[i].Offset, v, n * sizeof(float)); + return 1; + } + } + return 0; +} + +void ShaderBase::InitUniforms(ID3D10Blob* s) +{ + ID3D10ShaderReflection* ref = NULL; + D3D10ReflectShader(s->GetBufferPointer(), s->GetBufferSize(), &ref); + ID3D10ShaderReflectionConstantBuffer* buf = ref->GetConstantBufferByIndex(0); + D3D10_SHADER_BUFFER_DESC bufd; + if (FAILED(buf->GetDesc(&bufd))) + { + UniformsSize = 0; + if (UniformData) + { + OVR_FREE(UniformData); + UniformData = 0; + } + return; + } + + for(unsigned i = 0; i < bufd.Variables; i++) + { + ID3D10ShaderReflectionVariable* var = buf->GetVariableByIndex(i); + if (var) + { + D3D10_SHADER_VARIABLE_DESC vd; + if (SUCCEEDED(var->GetDesc(&vd))) + { + Uniform u; + u.Name = vd.Name; + u.Offset = vd.StartOffset; + u.Size = vd.Size; + UniformInfo.PushBack(u); + } + } + } + + UniformsSize = bufd.Size; + UniformData = (unsigned char*)OVR_ALLOC(bufd.Size); +} + +void ShaderBase::UpdateBuffer(Buffer* buf) +{ + if (UniformsSize) + { + buf->Data(Buffer_Uniform, UniformData, UniformsSize); + } +} + + +//------------------------------------------------------------------------------------- +// ***** Texture +// +Texture::Texture(RenderDevice* ren, int fmt, int w, int h) + : Ren(ren), Tex(NULL), TexSv(NULL), TexRtv(NULL), TexDsv(NULL), Width(w), Height(h) +{ + OVR_UNUSED(fmt); + Sampler = Ren->GetSamplerState(0); +} + +Texture::~Texture() +{ +} + +void Texture::Set(int slot, RenderTiny::ShaderStage stage) const +{ + Ren->SetTexture(stage, slot, this); +} + +void Texture::SetSampleMode(int sm) +{ + Sampler = Ren->GetSamplerState(sm); +} + + + +//------------------------------------------------------------------------------------- +// ***** Render Device + +RenderDevice::RenderDevice(const RendererParams& p, HWND window) +{ + RECT rc; + GetClientRect(window, &rc); + UINT width = rc.right - rc.left; + UINT height = rc.bottom - rc.top; + WindowWidth = width; + WindowHeight = height; + Window = window; + Params = p; + + HRESULT hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&DXGIFactory.GetRawRef())); + if (FAILED(hr)) + return; + + // Find the adapter & output (monitor) to use for fullscreen, based on the reported name of the HMD's monitor. + if (Params.MonitorName.GetLength() > 0) + { + for(UINT AdapterIndex = 0; ; AdapterIndex++) + { + HRESULT hr = DXGIFactory->EnumAdapters(AdapterIndex, &Adapter.GetRawRef()); + if (hr == DXGI_ERROR_NOT_FOUND) + break; + + DXGI_ADAPTER_DESC Desc; + Adapter->GetDesc(&Desc); + + UpdateMonitorOutputs(); + + if (FullscreenOutput) + break; + } + + if (!FullscreenOutput) + Adapter = NULL; + } + + if (!Adapter) + { + DXGIFactory->EnumAdapters(0, &Adapter.GetRawRef()); + } + + int flags = 0; + + hr = D3D10CreateDevice(Adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D1x_(SDK_VERSION), + &Device.GetRawRef()); + Context = Device; + Context->AddRef(); + + if (FAILED(hr)) + return; + + if (!RecreateSwapChain()) + return; + + if (Params.Fullscreen) + SwapChain->SetFullscreenState(1, FullscreenOutput); + + CurRenderTarget = NULL; + for(int i = 0; i < Shader_Count; i++) + { + UniformBuffers[i] = *CreateBuffer(); + MaxTextureSet[i] = 0; + } + + ID3D10Blob* vsData = CompileShader("vs_4_0", DirectVertexShaderSrc); + VertexShaders[VShader_MV] = *new VertexShader(this, vsData); + for(int i = 1; i < VShader_Count; i++) + { + VertexShaders[i] = *new VertexShader(this, CompileShader("vs_4_0", VShaderSrcs[i])); + } + + for(int i = 0; i < FShader_Count; i++) + { + PixelShaders[i] = *new PixelShader(this, CompileShader("ps_4_0", FShaderSrcs[i])); + } + + SPInt bufferSize = vsData->GetBufferSize(); + const void* buffer = vsData->GetBufferPointer(); + ID3D1xInputLayout** objRef = &ModelVertexIL.GetRawRef(); + + HRESULT validate = Device->CreateInputLayout(ModelVertexDesc, sizeof(ModelVertexDesc)/sizeof(D3D1x_(INPUT_ELEMENT_DESC)), + buffer, bufferSize, objRef); + OVR_UNUSED(validate); + + Ptr<ShaderSet> gouraudShaders = *new ShaderSet(); + gouraudShaders->SetShader(VertexShaders[VShader_MVP]); + gouraudShaders->SetShader(PixelShaders[FShader_Gouraud]); + DefaultFill = *new ShaderFill(gouraudShaders); + + D3D1x_(BLEND_DESC) bm; + memset(&bm, 0, sizeof(bm)); + bm.BlendEnable[0] = true; + bm.BlendOp = bm.BlendOpAlpha = D3D1x_(BLEND_OP_ADD); + bm.SrcBlend = bm.SrcBlendAlpha = D3D1x_(BLEND_SRC_ALPHA); + bm.DestBlend = bm.DestBlendAlpha = D3D1x_(BLEND_INV_SRC_ALPHA); + bm.RenderTargetWriteMask[0] = D3D1x_(COLOR_WRITE_ENABLE_ALL); + Device->CreateBlendState(&bm, &BlendState.GetRawRef()); + + D3D1x_(RASTERIZER_DESC) rs; + memset(&rs, 0, sizeof(rs)); + rs.AntialiasedLineEnable = true; + rs.CullMode = D3D1x_(CULL_BACK); + rs.DepthClipEnable = true; + rs.FillMode = D3D1x_(FILL_SOLID); + Device->CreateRasterizerState(&rs, &Rasterizer.GetRawRef()); + + QuadVertexBuffer = *CreateBuffer(); + const RenderTiny::Vertex QuadVertices[] = + { Vertex(Vector3f(0, 1, 0)), Vertex(Vector3f(1, 1, 0)), + Vertex(Vector3f(0, 0, 0)), Vertex(Vector3f(1, 0, 0)) }; + QuadVertexBuffer->Data(Buffer_Vertex, QuadVertices, sizeof(QuadVertices)); + + SetDepthMode(0, 0); +} + +RenderDevice::~RenderDevice() +{ + if (SwapChain && Params.Fullscreen) + { + SwapChain->SetFullscreenState(false, NULL); + } +} + + +// Implement static initializer function to create this class. +RenderTiny::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd) +{ + return new RenderDevice(rp, (HWND)oswnd); +} + + +// Fallback monitor enumeration in case newly plugged in monitor wasn't detected. +// Added originally for the FactoryTest app. +// New Outputs don't seem to be detected unless adapter is re-created, but that would also +// require us to re-initialize D3D10 (recreating objects, etc). This bypasses that for "fake" +// fullscreen modes. +BOOL CALLBACK MonitorEnumFunc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData) +{ + RenderDevice* renderer = (RenderDevice*)dwData; + + MONITORINFOEX monitor; + monitor.cbSize = sizeof(monitor); + + if (::GetMonitorInfo(hMonitor, &monitor) && monitor.szDevice[0]) + { + DISPLAY_DEVICE dispDev; + memset(&dispDev, 0, sizeof(dispDev)); + dispDev.cb = sizeof(dispDev); + + if (::EnumDisplayDevices(monitor.szDevice, 0, &dispDev, 0)) + { + if (strstr(String(dispDev.DeviceName).ToCStr(), renderer->GetParams().MonitorName.ToCStr())) + { + renderer->FSDesktopX = monitor.rcMonitor.left; + renderer->FSDesktopY = monitor.rcMonitor.top; + return FALSE; + } + } + } + + return TRUE; +} + + +void RenderDevice::UpdateMonitorOutputs() +{ + HRESULT hr; + + bool deviceNameFound = false; + + for(UINT OutputIndex = 0; ; OutputIndex++) + { + Ptr<IDXGIOutput> Output; + hr = Adapter->EnumOutputs(OutputIndex, &Output.GetRawRef()); + if (hr == DXGI_ERROR_NOT_FOUND) + { + break; + } + + DXGI_OUTPUT_DESC OutDesc; + Output->GetDesc(&OutDesc); + + MONITORINFOEX monitor; + monitor.cbSize = sizeof(monitor); + if (::GetMonitorInfo(OutDesc.Monitor, &monitor) && monitor.szDevice[0]) + { + DISPLAY_DEVICE dispDev; + memset(&dispDev, 0, sizeof(dispDev)); + dispDev.cb = sizeof(dispDev); + + if (::EnumDisplayDevices(monitor.szDevice, 0, &dispDev, 0)) + { + if (strstr(String(dispDev.DeviceName).ToCStr(), Params.MonitorName.ToCStr())) + { + deviceNameFound = true; + FullscreenOutput = Output; + FSDesktopX = monitor.rcMonitor.left; + FSDesktopY = monitor.rcMonitor.top; + break; + } + } + } + } + + if (!deviceNameFound && !Params.MonitorName.IsEmpty()) + { + EnumDisplayMonitors(0, 0, MonitorEnumFunc, (LPARAM)this); + } +} + +bool RenderDevice::RecreateSwapChain() +{ + DXGI_SWAP_CHAIN_DESC scDesc; + memset(&scDesc, 0, sizeof(scDesc)); + scDesc.BufferCount = 1; + scDesc.BufferDesc.Width = WindowWidth; + scDesc.BufferDesc.Height = WindowHeight; + scDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + scDesc.BufferDesc.RefreshRate.Numerator = 60; + scDesc.BufferDesc.RefreshRate.Denominator = 1; + scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + scDesc.OutputWindow = Window; + scDesc.SampleDesc.Count = Params.Multisample; + scDesc.SampleDesc.Quality = 0; + scDesc.Windowed = (Params.Fullscreen != Display_Fullscreen); + scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + if (SwapChain) + { + SwapChain->SetFullscreenState(FALSE, NULL); + SwapChain->Release(); + SwapChain = NULL; + } + + Ptr<IDXGISwapChain> newSC; + if (FAILED(DXGIFactory->CreateSwapChain(Device, &scDesc, &newSC.GetRawRef()))) + return false; + SwapChain = newSC; + + BackBuffer = NULL; + BackBufferRT = NULL; + HRESULT hr = SwapChain->GetBuffer(0, __uuidof(ID3D1xTexture2D), (void**)&BackBuffer.GetRawRef()); + if (FAILED(hr)) + return false; + + hr = Device->CreateRenderTargetView(BackBuffer, NULL, &BackBufferRT.GetRawRef()); + if (FAILED(hr)) + return false; + + Texture* depthBuffer = GetDepthBuffer(WindowWidth, WindowHeight, Params.Multisample); + CurDepthBuffer = depthBuffer; + if (CurRenderTarget == NULL) + { + Context->OMSetRenderTargets(1, &BackBufferRT.GetRawRef(), depthBuffer->TexDsv); + } + return true; +} + +bool RenderDevice::SetParams(const RendererParams& newParams) +{ + String oldMonitor = Params.MonitorName; + + Params = newParams; + if (newParams.MonitorName != oldMonitor) + { + UpdateMonitorOutputs(); + } + + // Cause this to be recreated with the new multisample mode. + pSceneColorTex = NULL; + return RecreateSwapChain(); +} + + +bool RenderDevice::SetFullscreen(DisplayMode fullscreen) +{ + if (fullscreen == Params.Fullscreen) + return true; + + HRESULT hr = SwapChain->SetFullscreenState(fullscreen, fullscreen ? FullscreenOutput : NULL); + if (FAILED(hr)) + { + return false; + } + + Params.Fullscreen = fullscreen; + return true; +} + +void RenderDevice::SetRealViewport(const Viewport& vp) +{ + D3DViewport.Width = vp.w; + D3DViewport.Height = vp.h; + D3DViewport.MinDepth = 0; + D3DViewport.MaxDepth = 1; + D3DViewport.TopLeftX = vp.x; + D3DViewport.TopLeftY = vp.y; + Context->RSSetViewports(1, &D3DViewport); +} + +static int GetDepthStateIndex(bool enable, bool write, RenderDevice::CompareFunc func) +{ + if (!enable) + return 0; + return 1 + int(func) * 2 + write; +} + +void RenderDevice::SetDepthMode(bool enable, bool write, CompareFunc func) +{ + int index = GetDepthStateIndex(enable, write, func); + if (DepthStates[index]) + { + CurDepthState = DepthStates[index]; + Context->OMSetDepthStencilState(DepthStates[index], 0); + return; + } + + D3D1x_(DEPTH_STENCIL_DESC) dss; + memset(&dss, 0, sizeof(dss)); + dss.DepthEnable = enable; + switch(func) + { + case Compare_Always: dss.DepthFunc = D3D1x_(COMPARISON_ALWAYS); break; + case Compare_Less: dss.DepthFunc = D3D1x_(COMPARISON_LESS); break; + case Compare_Greater: dss.DepthFunc = D3D1x_(COMPARISON_GREATER); break; + default: + assert(0); + } + dss.DepthWriteMask = write ? D3D1x_(DEPTH_WRITE_MASK_ALL) : D3D1x_(DEPTH_WRITE_MASK_ZERO); + Device->CreateDepthStencilState(&dss, &DepthStates[index].GetRawRef()); + Context->OMSetDepthStencilState(DepthStates[index], 0); + CurDepthState = DepthStates[index]; +} + +Texture* RenderDevice::GetDepthBuffer(int w, int h, int ms) +{ + for(unsigned i = 0; i < DepthBuffers.GetSize(); i++) + { + if (w == DepthBuffers[i]->Width && h == DepthBuffers[i]->Height && + ms == DepthBuffers[i]->Samples) + return DepthBuffers[i]; + } + + Ptr<Texture> newDepth = *CreateTexture(Texture_Depth | Texture_RenderTarget | ms, w, h, NULL); + if (newDepth == NULL) + { + OVR_DEBUG_LOG(("Failed to get depth buffer.")); + return NULL; + } + + DepthBuffers.PushBack(newDepth); + return newDepth.GetPtr(); +} + +void RenderDevice::Clear(float r, float g, float b, float a, float depth) +{ + const float color[] = {r, g, b, a}; + + // Needed for each eye to do its own clear, since ClearRenderTargetView doesn't honor viewport. + + // Save state that is affected by clearing this way + ID3D1xDepthStencilState* oldDepthState = CurDepthState; + StandardUniformData clearUniforms; + + SetDepthMode(true, true, Compare_Always); + + Context->IASetInputLayout(ModelVertexIL); + Context->GSSetShader(NULL); + + ID3D1xShaderResourceView* sv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + if (MaxTextureSet[Shader_Fragment]) + { + Context->PSSetShaderResources(0, MaxTextureSet[Shader_Fragment], sv); + } + + ID3D1xBuffer* vertexBuffer = QuadVertexBuffer->GetBuffer(); + UINT vertexStride = sizeof(Vertex); + UINT vertexOffset = 0; + Context->IASetVertexBuffers(0, 1, &vertexBuffer, &vertexStride, &vertexOffset); + + clearUniforms.View = Matrix4f(2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 0, 0, + -1, -1, depth, 1); + UniformBuffers[Shader_Vertex]->Data(Buffer_Uniform, &clearUniforms, sizeof(clearUniforms)); + + ID3D1xBuffer* vertexConstants = UniformBuffers[Shader_Vertex]->GetBuffer(); + Context->VSSetConstantBuffers(0, 1, &vertexConstants); + Context->IASetPrimitiveTopology(D3D1x_(PRIMITIVE_TOPOLOGY_TRIANGLESTRIP)); + VertexShaders[VShader_MV]->Set(Prim_TriangleStrip); + PixelShaders[FShader_Solid]->Set(Prim_TriangleStrip); + + UniformBuffers[Shader_Pixel]->Data(Buffer_Uniform, color, sizeof(color)); + PixelShaders[FShader_Solid]->SetUniformBuffer(UniformBuffers[Shader_Pixel]); + + // Clear Viewport + Context->OMSetBlendState(NULL, NULL, 0xffffffff); + Context->Draw(4, 0); + + // reset + CurDepthState = oldDepthState; + Context->OMSetDepthStencilState(CurDepthState, 0); +} + +// Buffers + +Buffer* RenderDevice::CreateBuffer() +{ + return new Buffer(this); +} + + +ID3D10Blob* RenderDevice::CompileShader(const char* profile, const char* src, const char* mainName) +{ + ID3D10Blob* shader; + ID3D10Blob* errors; + HRESULT hr = D3DCompile(src, strlen(src), NULL, NULL, NULL, mainName, profile, + 0, 0, &shader, &errors); + if (FAILED(hr)) + { + OVR_DEBUG_LOG(("Compiling D3D shader for %s failed\n%s\n\n%s", + profile, src, errors->GetBufferPointer())); + OutputDebugStringA((char*)errors->GetBufferPointer()); + return NULL; + } + if (errors) + { + errors->Release(); + } + return shader; +} + +void RenderDevice::SetCommonUniformBuffer(int i, RenderTiny::Buffer* buffer) +{ + CommonUniforms[i] = (Buffer*)buffer; + + Context->PSSetConstantBuffers(1, 1, &CommonUniforms[1]->D3DBuffer.GetRawRef()); + Context->VSSetConstantBuffers(1, 1, &CommonUniforms[1]->D3DBuffer.GetRawRef()); +} + +RenderTiny::Shader *RenderDevice::LoadBuiltinShader(ShaderStage stage, int shader) +{ + switch(stage) + { + case Shader_Vertex: + return VertexShaders[shader]; + case Shader_Pixel: + return PixelShaders[shader]; + default: + return NULL; + } +} + + +ID3D1xSamplerState* RenderDevice::GetSamplerState(int sm) +{ + if (SamplerStates[sm]) + return SamplerStates[sm]; + + D3D1x_(SAMPLER_DESC) ss; + memset(&ss, 0, sizeof(ss)); + if (sm & Sample_Clamp) + ss.AddressU = ss.AddressV = ss.AddressW = D3D1x_(TEXTURE_ADDRESS_CLAMP); + else if (sm & Sample_ClampBorder) + ss.AddressU = ss.AddressV = ss.AddressW = D3D1x_(TEXTURE_ADDRESS_BORDER); + else + ss.AddressU = ss.AddressV = ss.AddressW = D3D1x_(TEXTURE_ADDRESS_WRAP); + + if (sm & Sample_Nearest) + { + ss.Filter = D3D1x_(FILTER_MIN_MAG_MIP_POINT); + } + else if (sm & Sample_Anisotropic) + { + ss.Filter = D3D1x_(FILTER_ANISOTROPIC); + ss.MaxAnisotropy = 8; + } + else + { + ss.Filter = D3D1x_(FILTER_MIN_MAG_MIP_LINEAR); + } + ss.MaxLOD = 15; + Device->CreateSamplerState(&ss, &SamplerStates[sm].GetRawRef()); + return SamplerStates[sm]; +} + + +void RenderDevice::SetTexture(RenderTiny::ShaderStage stage, int slot, const Texture* t) +{ + if (MaxTextureSet[stage] <= slot) + MaxTextureSet[stage] = slot + 1; + + ID3D1xShaderResourceView* sv = t ? t->TexSv : NULL; + switch(stage) + { + case Shader_Fragment: + Context->PSSetShaderResources(slot, 1, &sv); + if (t) + { + Context->PSSetSamplers(slot, 1, &t->Sampler.GetRawRef()); + } + break; + + case Shader_Vertex: + Context->VSSetShaderResources(slot, 1, &sv); + break; + } +} + +Texture* RenderDevice::CreateTexture(int format, int width, int height, const void* data, int mipcount) +{ + OVR_UNUSED(mipcount); + + DXGI_FORMAT d3dformat; + int bpp; + switch(format & Texture_TypeMask) + { + case Texture_RGBA: + bpp = 4; + d3dformat = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case Texture_Depth: + bpp = 0; + d3dformat = DXGI_FORMAT_D32_FLOAT; + break; + default: + return NULL; + } + + int samples = (format & Texture_SamplesMask); + if (samples < 1) + { + samples = 1; + } + + Texture* NewTex = new Texture(this, format, width, height); + NewTex->Samples = samples; + + D3D1x_(TEXTURE2D_DESC) dsDesc; + dsDesc.Width = width; + dsDesc.Height = height; + dsDesc.MipLevels = (format == (Texture_RGBA | Texture_GenMipmaps) && data) ? GetNumMipLevels(width, height) : 1; + dsDesc.ArraySize = 1; + dsDesc.Format = d3dformat; + dsDesc.SampleDesc.Count = samples; + dsDesc.SampleDesc.Quality = 0; + dsDesc.Usage = D3D1x_(USAGE_DEFAULT); + dsDesc.BindFlags = D3D1x_(BIND_SHADER_RESOURCE); + dsDesc.CPUAccessFlags = 0; + dsDesc.MiscFlags = 0; + + if (format & Texture_RenderTarget) + { + if ((format & Texture_TypeMask) == Texture_Depth) + { // We don't use depth textures, and creating them in d3d10 requires different options. + dsDesc.BindFlags = D3D1x_(BIND_DEPTH_STENCIL); + } + else + { + dsDesc.BindFlags |= D3D1x_(BIND_RENDER_TARGET); + } + } + + HRESULT hr = Device->CreateTexture2D(&dsDesc, NULL, &NewTex->Tex.GetRawRef()); + if (FAILED(hr)) + { + OVR_DEBUG_LOG_TEXT(("Failed to create 2D D3D texture.")); + NewTex->Release(); + return NULL; + } + if (dsDesc.BindFlags & D3D1x_(BIND_SHADER_RESOURCE)) + { + Device->CreateShaderResourceView(NewTex->Tex, NULL, &NewTex->TexSv.GetRawRef()); + } + + if (data) + { + Context->UpdateSubresource(NewTex->Tex, 0, NULL, data, width * bpp, width * height * bpp); + if (format == (Texture_RGBA | Texture_GenMipmaps)) + { + int srcw = width, srch = height; + int level = 0; + UByte* mipmaps = NULL; + do + { + level++; + int mipw = srcw >> 1; + if (mipw < 1) + { + mipw = 1; + } + int miph = srch >> 1; + if (miph < 1) + { + miph = 1; + } + if (mipmaps == NULL) + { + mipmaps = (UByte*)OVR_ALLOC(mipw * miph * 4); + } + FilterRgba2x2(level == 1 ? (const UByte*)data : mipmaps, srcw, srch, mipmaps); + Context->UpdateSubresource(NewTex->Tex, level, NULL, mipmaps, mipw * bpp, miph * bpp); + srcw = mipw; + srch = miph; + } + while(srcw > 1 || srch > 1); + + if (mipmaps != NULL) + { + OVR_FREE(mipmaps); + } + } + } + + if (format & Texture_RenderTarget) + { + if ((format & Texture_TypeMask) == Texture_Depth) + { + Device->CreateDepthStencilView(NewTex->Tex, NULL, &NewTex->TexDsv.GetRawRef()); + } + else + { + Device->CreateRenderTargetView(NewTex->Tex, NULL, &NewTex->TexRtv.GetRawRef()); + } + } + + return NewTex; +} + + +// Rendering + +void RenderDevice::BeginRendering() +{ + Context->RSSetState(Rasterizer); +} + +void RenderDevice::SetRenderTarget(RenderTiny::Texture* colorTex, + RenderTiny::Texture* depth, RenderTiny::Texture* stencil) +{ + OVR_UNUSED(stencil); + + CurRenderTarget = (Texture*)colorTex; + if (colorTex == NULL) + { + Texture* newDepthBuffer = GetDepthBuffer(WindowWidth, WindowHeight, Params.Multisample); + if (newDepthBuffer == NULL) + { + OVR_DEBUG_LOG(("New depth buffer creation failed.")); + } + if (newDepthBuffer != NULL) + { + CurDepthBuffer = GetDepthBuffer(WindowWidth, WindowHeight, Params.Multisample); + Context->OMSetRenderTargets(1, &BackBufferRT.GetRawRef(), CurDepthBuffer->TexDsv); + } + return; + } + if (depth == NULL) + { + depth = GetDepthBuffer(colorTex->GetWidth(), colorTex->GetHeight(), CurRenderTarget->Samples); + } + + ID3D1xShaderResourceView* sv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + if (MaxTextureSet[Shader_Fragment]) + { + Context->PSSetShaderResources(0, MaxTextureSet[Shader_Fragment], sv); + } + memset(MaxTextureSet, 0, sizeof(MaxTextureSet)); + + CurDepthBuffer = (Texture*)depth; + Context->OMSetRenderTargets(1, &((Texture*)colorTex)->TexRtv.GetRawRef(), ((Texture*)depth)->TexDsv); +} + + +void RenderDevice::SetWorldUniforms(const Matrix4f& proj) +{ + StdUniforms.Proj = proj.Transposed(); + // Shader constant buffers cannot be partially updated. +} + + +void RenderDevice::Render(const Matrix4f& matrix, Model* model) +{ + // Store data in buffers if not already + if (!model->VertexBuffer) + { + Ptr<Buffer> vb = *CreateBuffer(); + vb->Data(Buffer_Vertex, &model->Vertices[0], model->Vertices.GetSize() * sizeof(Vertex)); + model->VertexBuffer = vb; + } + if (!model->IndexBuffer) + { + Ptr<Buffer> ib = *CreateBuffer(); + ib->Data(Buffer_Index, &model->Indices[0], model->Indices.GetSize() * 2); + model->IndexBuffer = ib; + } + + Render(model->Fill ? model->Fill : DefaultFill, + model->VertexBuffer, model->IndexBuffer, + matrix, 0, (unsigned)model->Indices.GetSize(), model->GetPrimType()); +} + +void RenderDevice::Render(const ShaderFill* fill, RenderTiny::Buffer* vertices, RenderTiny::Buffer* indices, + const Matrix4f& matrix, int offset, int count, PrimitiveType rprim) +{ + Context->IASetInputLayout(ModelVertexIL); + if (indices) + { + Context->IASetIndexBuffer(((Buffer*)indices)->GetBuffer(), DXGI_FORMAT_R16_UINT, 0); + } + + ID3D1xBuffer* vertexBuffer = ((Buffer*)vertices)->GetBuffer(); + UINT vertexStride = sizeof(Vertex); + UINT vertexOffset = offset; + Context->IASetVertexBuffers(0, 1, &vertexBuffer, &vertexStride, &vertexOffset); + + ShaderSet* shaders = ((ShaderFill*)fill)->GetShaders(); + + ShaderBase* vshader = ((ShaderBase*)shaders->GetShader(Shader_Vertex)); + unsigned char* vertexData = vshader->UniformData; + if (vertexData) + { + StandardUniformData* stdUniforms = (StandardUniformData*) vertexData; + stdUniforms->View = matrix.Transposed(); + stdUniforms->Proj = StdUniforms.Proj; + UniformBuffers[Shader_Vertex]->Data(Buffer_Uniform, vertexData, vshader->UniformsSize); + vshader->SetUniformBuffer(UniformBuffers[Shader_Vertex]); + } + + for(int i = Shader_Vertex + 1; i < Shader_Count; i++) + if (shaders->GetShader(i)) + { + ((ShaderBase*)shaders->GetShader(i))->UpdateBuffer(UniformBuffers[i]); + ((ShaderBase*)shaders->GetShader(i))->SetUniformBuffer(UniformBuffers[i]); + } + + D3D1x_(PRIMITIVE_TOPOLOGY) prim; + switch(rprim) + { + case Prim_Triangles: + prim = D3D1x_(PRIMITIVE_TOPOLOGY_TRIANGLELIST); + break; + case Prim_Lines: + prim = D3D1x_(PRIMITIVE_TOPOLOGY_LINELIST); + break; + case Prim_TriangleStrip: + prim = D3D1x_(PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + break; + default: + assert(0); + return; + } + Context->IASetPrimitiveTopology(prim); + + fill->Set(rprim); + + if (indices) + { + Context->DrawIndexed(count, 0, 0); + } + else + { + Context->Draw(count, 0); + } +} + + +void RenderDevice::Present() +{ + SwapChain->Present(0, 0); +} + +void RenderDevice::ForceFlushGPU() +{ + D3D1x_QUERY_DESC queryDesc = { D3D1x_(QUERY_EVENT), 0 }; + Ptr<ID3D1xQuery> query; + BOOL done = FALSE; + + if (Device->CreateQuery(&queryDesc, &query.GetRawRef()) == S_OK) + { + // Begin() not used for EVENT query. + query->End(); + // GetData will returns S_OK for both done == TRUE or FALSE. + // Exit on failure to avoid infinite loop. + do { } + while(!done && !FAILED(query->GetData(&done, sizeof(BOOL), 0))); + } +} + +}}} + |