diff options
Diffstat (limited to 'o3d/command_buffer/service/gapi_d3d9.cc')
-rw-r--r-- | o3d/command_buffer/service/gapi_d3d9.cc | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/o3d/command_buffer/service/gapi_d3d9.cc b/o3d/command_buffer/service/gapi_d3d9.cc new file mode 100644 index 0000000..1d840eb --- /dev/null +++ b/o3d/command_buffer/service/gapi_d3d9.cc @@ -0,0 +1,392 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +// This file contains the implementation of the GAPID3D9 class. + +#include "command_buffer/service/gapi_d3d9.h" + +namespace command_buffer { +namespace o3d { + +GAPID3D9::GAPID3D9() + : d3d_module_(NULL), + d3dx_module_(NULL), + d3d_(NULL), + d3d_device_(NULL), + hwnd_(NULL), + current_vertex_struct_(0), + validate_streams_(true), + max_vertices_(0), + current_effect_id_(0), + validate_effect_(true), + current_effect_(NULL), + vertex_buffers_(), + index_buffers_(), + vertex_structs_(), + back_buffer_surface_(NULL), + back_buffer_depth_surface_(NULL), + current_surface_id_(kInvalidResource), + current_depth_surface_id_(kInvalidResource), + direct3d_create9_(NULL), + get_shader_constant_table_(NULL), + create_effect_(NULL), + get_shader_input_semantics_(NULL) {} + +GAPID3D9::~GAPID3D9() {} + +// Initializes a D3D interface and device, and sets basic states. +bool GAPID3D9::Initialize() { + if (!FindDirect3DFunctions()) { + Destroy(); + return false; + } + + d3d_ = Direct3DCreate(D3D_SDK_VERSION); + if (NULL == d3d_) { + LOG(ERROR) << "Failed to create the initial D3D9 Interface"; + Destroy(); + return false; + } + d3d_device_ = NULL; + + D3DDISPLAYMODE d3ddm; + d3d_->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); + // NOTE: make sure the backbuffer matches this format, as it is + // currently currently assumed to be 32-bit 8X8R8G8B + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // wait for vsync + // Note: SwapEffect=DISCARD is req. for multisample to function + // Note: AutoDepthStencilFormat is 16-bit (not the usual 8-bit) + + // query multisampling + const int kNumTypesToCheck = 4; + D3DMULTISAMPLE_TYPE multisample_types[] = { D3DMULTISAMPLE_5_SAMPLES, + D3DMULTISAMPLE_4_SAMPLES, + D3DMULTISAMPLE_2_SAMPLES, + D3DMULTISAMPLE_NONE }; + DWORD multisample_quality = 0; + for (int i = 0; i < kNumTypesToCheck; ++i) { + // check back-buffer for multisampling at level "i"; + // back buffer = 32-bit XRGB (i.e. no alpha) + if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, + true, // result is windowed + multisample_types[i], + &multisample_quality))) { + // back buffer succeeded, now check depth-buffer + // depth buffer = 24-bit, stencil = 8-bit + // NOTE: 8-bit not 16-bit like the D3DPRESENT_PARAMETERS + if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + D3DFMT_D24S8, + true, // result is windowed + multisample_types[i], + &multisample_quality))) { + d3dpp.MultiSampleType = multisample_types[i]; + d3dpp.MultiSampleQuality = multisample_quality - 1; + break; + } + } + } + // D3DCREATE_FPU_PRESERVE is there because Firefox 3 relies on specific FPU + // flags for its UI rendering. Apparently Firefox 2 does not, though we don't + // currently propagate that info. + // TODO: check if FPU_PRESERVE has a significant perf hit, in which + // case find out if we can disable it for Firefox 2/other browsers, and/or if + // it makes sense to switch FPU flags before/after every DX call. + DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE; + if (!SUCCEEDED(d3d_->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hwnd_, + flags, + &d3dpp, + &d3d_device_))) { + LOG(ERROR) << "Failed to create the D3D Device"; + Destroy(); + return false; + } + // initialise the d3d graphics state. + HR(d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZENABLE, TRUE)); + HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE)); + return true; +} + +// Deletes the D3D9 Device and releases the D3D interface. +void GAPID3D9::Destroy() { + vertex_buffers_.DestroyAllResources(); + index_buffers_.DestroyAllResources(); + vertex_structs_.DestroyAllResources(); + effects_.DestroyAllResources(); + effect_params_.DestroyAllResources(); + textures_.DestroyAllResources(); + samplers_.DestroyAllResources(); + render_surfaces_.DestroyAllResources(); + depth_surfaces_.DestroyAllResources(); + if (d3d_device_) { + d3d_device_->Release(); + d3d_device_ = NULL; + } + if (d3d_) { + d3d_->Release(); + d3d_ = NULL; + } + if (d3dx_module_) { + FreeLibrary(d3dx_module_); + d3dx_module_ = NULL; + get_shader_constant_table_ = NULL; + create_effect_ = NULL; + get_shader_input_semantics_ = NULL; + } + if (d3d_module_) { + FreeLibrary(d3d_module_); + d3d_module_ = NULL; + direct3d_create9_ = NULL; + } +} + +// Begins the frame. +void GAPID3D9::BeginFrame() { + HR(d3d_device_->GetRenderTarget(0, &back_buffer_surface_)); + HR(d3d_device_->GetDepthStencilSurface(&back_buffer_depth_surface_)); + HR(d3d_device_->BeginScene()); +} + +// Ends the frame, presenting the back buffer. +void GAPID3D9::EndFrame() { + DirtyEffect(); + HR(d3d_device_->EndScene()); + HR(d3d_device_->Present(NULL, NULL, NULL, NULL)); + + // Release the back-buffer references. + back_buffer_surface_ = NULL; + back_buffer_depth_surface_ = NULL; +} + +// Clears the selected buffers. +void GAPID3D9::Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + DWORD flags = (buffers & kColor ? D3DCLEAR_TARGET : 0) | + (buffers & kDepth ? D3DCLEAR_ZBUFFER : 0) | + (buffers & kStencil ? D3DCLEAR_STENCIL : 0); + HR(d3d_device_->Clear(0, + NULL, + flags, + D3DCOLOR_COLORVALUE(color.red, + color.green, + color.blue, + color.alpha), + depth, + stencil)); +} + +// Sets the viewport. +void GAPID3D9::SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max) { + D3DVIEWPORT9 viewport = {x, y, width, height, z_min, z_max}; + HR(d3d_device_->SetViewport(&viewport)); +} + +// Converts an unsigned int RGBA color into an unsigned int ARGB (DirectX) +// color. +static unsigned int RGBAToARGB(unsigned int rgba) { + return (rgba >> 8) | (rgba << 24); +} + +// Sets the current VertexStruct. Just keep track of the ID. +parse_error::ParseError GAPID3D9::SetVertexStruct(ResourceId id) { + current_vertex_struct_ = id; + validate_streams_ = true; + return parse_error::kParseNoError; +} + +bool GAPID3D9::FindDirect3DFunctions() { + d3d_module_ = LoadLibrary(TEXT("d3d9.dll")); + if (NULL == d3d_module_) { + LOG(ERROR) << "Failed to load d3d9.dll"; + return false; + } + + direct3d_create9_ = reinterpret_cast<Direct3DCreate9Proc>( + GetProcAddress(d3d_module_, "Direct3DCreate9")); + if (NULL == direct3d_create9_) { + LOG(ERROR) << "Failed to find Direct3DCreate9 in d3d9.dll"; + Destroy(); + return false; + } + + d3dx_module_ = LoadLibrary(TEXT("d3dx9_36.dll")); + if (NULL == d3d_module_) { + LOG(ERROR) << "Failed to load d3dx9_36.dll"; + return false; + } + + get_shader_constant_table_ = reinterpret_cast<D3DXGetShaderConstantTableProc>( + GetProcAddress(d3dx_module_, "D3DXGetShaderConstantTable")); + if (NULL == get_shader_constant_table_) { + LOG(ERROR) << "Failed to find D3DXGetShaderConstantTable in d3dx9_36.dll"; + Destroy(); + return false; + } + + create_effect_ = reinterpret_cast<D3DXCreateEffectProc>( + GetProcAddress(d3dx_module_, "D3DXCreateEffect")); + if (NULL == create_effect_) { + LOG(ERROR) << "Failed to find D3DXCreateEffect in d3dx9_36.dll"; + Destroy(); + return false; + } + + get_shader_input_semantics_ = + reinterpret_cast<D3DXGetShaderInputSemanticsProc>( + GetProcAddress(d3dx_module_, "D3DXGetShaderInputSemantics")); + if (NULL == get_shader_input_semantics_) { + LOG(ERROR) << "Failed to find D3DXGetShaderInputSemantics in d3dx9_36.dll"; + Destroy(); + return false; + } + + return true; +} + +// Sets in D3D the input streams of the current vertex struct. +bool GAPID3D9::ValidateStreams() { + DCHECK(validate_streams_); + VertexStructD3D9 *vertex_struct = vertex_structs_.Get(current_vertex_struct_); + if (!vertex_struct) { + LOG(ERROR) << "Drawing with invalid streams."; + return false; + } + max_vertices_ = vertex_struct->SetStreams(this); + validate_streams_ = false; + return max_vertices_ > 0; +} + +// Converts a GAPID3D9::PrimitiveType to a D3DPRIMITIVETYPE. +static D3DPRIMITIVETYPE D3DPrimitive( + PrimitiveType primitive_type) { + switch (primitive_type) { + case kPoints: + return D3DPT_POINTLIST; + case kLines: + return D3DPT_LINELIST; + case kLineStrips: + return D3DPT_LINESTRIP; + case kTriangles: + return D3DPT_TRIANGLELIST; + case kTriangleStrips: + return D3DPT_TRIANGLESTRIP; + case kTriangleFans: + return D3DPT_TRIANGLEFAN; + default: + LOG(FATAL) << "Invalid primitive type"; + return D3DPT_POINTLIST; + } +} + +// Draws with the current vertex struct. +parse_error::ParseError GAPID3D9::Draw( + PrimitiveType primitive_type, + unsigned int first, + unsigned int count) { + if (validate_streams_ && !ValidateStreams()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + if (validate_effect_ && !ValidateEffect()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + DCHECK(current_effect_); + if (!current_effect_->CommitParameters()) { + return parse_error::kParseInvalidArguments; + } + if (first + count > max_vertices_) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + HR(d3d_device_->DrawPrimitive(D3DPrimitive(primitive_type), first, count)); + return parse_error::kParseNoError; +} + +// Draws with the current vertex struct. +parse_error::ParseError GAPID3D9::DrawIndexed( + PrimitiveType primitive_type, + ResourceId index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(index_buffer_id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + if (validate_streams_ && !ValidateStreams()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + if (validate_effect_ && !ValidateEffect()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + DCHECK(current_effect_); + if (!current_effect_->CommitParameters()) { + return parse_error::kParseInvalidArguments; + } + if ((min_index >= max_vertices_) || (max_index > max_vertices_)) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + + HR(d3d_device_->SetIndices(index_buffer->d3d_index_buffer())); + HR(d3d_device_->DrawIndexedPrimitive(D3DPrimitive(primitive_type), 0, + min_index, max_index - min_index + 1, + first, count)); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer |