summaryrefslogtreecommitdiffstats
path: root/o3d/gpu/command_buffer/service/effect_d3d9.cc
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/gpu/command_buffer/service/effect_d3d9.cc')
-rw-r--r--o3d/gpu/command_buffer/service/effect_d3d9.cc679
1 files changed, 679 insertions, 0 deletions
diff --git a/o3d/gpu/command_buffer/service/effect_d3d9.cc b/o3d/gpu/command_buffer/service/effect_d3d9.cc
new file mode 100644
index 0000000..4bfae53
--- /dev/null
+++ b/o3d/gpu/command_buffer/service/effect_d3d9.cc
@@ -0,0 +1,679 @@
+/*
+ * 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 D3D9 versions of the
+// Effect resource.
+// This file also contains the related GAPID3D9 function implementations.
+
+#include "gpu/command_buffer/service/precompile.h"
+
+#include <algorithm>
+#include "gpu/command_buffer/service/d3d9_utils.h"
+#include "gpu/command_buffer/service/geometry_d3d9.h"
+#include "gpu/command_buffer/service/gapi_d3d9.h"
+#include "gpu/command_buffer/service/effect_d3d9.h"
+#include "gpu/command_buffer/service/sampler_d3d9.h"
+#include "gpu/command_buffer/service/effect_utils.h"
+
+// TODO: remove link-dependency on D3DX.
+
+namespace command_buffer {
+namespace o3d {
+
+// Logs the D3D effect error, from either the buffer, or GetLastError().
+static void LogFXError(LPD3DXBUFFER error_buffer) {
+ if (error_buffer) {
+ LPVOID compile_errors = error_buffer->GetBufferPointer();
+ LOG(ERROR) << "Failed to compile effect: "
+ << static_cast<char *>(compile_errors);
+ } else {
+ HLOCAL hLocal = NULL;
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ GetLastError(),
+ 0,
+ reinterpret_cast<wchar_t*>(&hLocal),
+ 0,
+ NULL);
+ wchar_t* msg = reinterpret_cast<wchar_t*>(LocalLock(hLocal));
+ LOG(ERROR) << "Failed to compile effect: " << msg;
+ LocalFree(hLocal);
+ }
+}
+
+EffectD3D9::EffectD3D9(GAPID3D9 *gapi,
+ ID3DXEffect *d3d_effect,
+ ID3DXConstantTable *fs_constant_table,
+ IDirect3DVertexShader9 *d3d_vertex_shader)
+ : gapi_(gapi),
+ d3d_effect_(d3d_effect),
+ fs_constant_table_(fs_constant_table),
+ d3d_vertex_shader_(d3d_vertex_shader),
+ sync_parameters_(false) {
+ for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) {
+ samplers_[i] = kInvalidResource;
+ }
+ SetStreams();
+}
+// Releases the D3D effect.
+EffectD3D9::~EffectD3D9() {
+ for (ParamList::iterator it = params_.begin(); it != params_.end(); ++it) {
+ (*it)->ResetEffect();
+ }
+ DCHECK(d3d_effect_);
+ d3d_effect_->Release();
+ DCHECK(fs_constant_table_);
+ fs_constant_table_->Release();
+ DCHECK(d3d_vertex_shader_);
+ d3d_vertex_shader_->Release();
+}
+
+// Compiles the effect, and checks that the effect conforms to what we expect
+// (no extra technique or pass in the effect code, since one is implicitly added
+// using the program entry points) and that it validates. If successful, wrap
+// the D3D effect into a new EffectD3D9.
+EffectD3D9 *EffectD3D9::Create(GAPID3D9 *gapi,
+ const String& effect_code,
+ const String& vertex_program_entry,
+ const String& fragment_program_entry) {
+ String prepared_effect = effect_code +
+ "technique Shaders { "
+ " pass p0 { "
+ " VertexShader = compile vs_2_0 " + vertex_program_entry + "();"
+ " PixelShader = compile ps_2_0 " + fragment_program_entry + "();"
+ " }"
+ "};";
+ ID3DXEffect *d3d_effect = NULL;
+ LPD3DXBUFFER error_buffer;
+ IDirect3DDevice9 *device = gapi->d3d_device();
+ if (gapi->D3DXCreateEffect(device,
+ prepared_effect.c_str(),
+ prepared_effect.size(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ &d3d_effect,
+ &error_buffer) != D3D_OK) {
+ LogFXError(error_buffer);
+ return NULL;
+ }
+ // check that .
+ D3DXEFFECT_DESC effect_desc;
+ HR(d3d_effect->GetDesc(&effect_desc));
+ if (effect_desc.Techniques != 1) {
+ LOG(ERROR) << "Only 1 technique is allowed in an effect.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ D3DXHANDLE technique = d3d_effect->GetTechnique(0);
+ DCHECK(technique);
+ if (d3d_effect->ValidateTechnique(technique) != D3D_OK) {
+ LOG(ERROR) << "Technique doesn't validate.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ D3DXTECHNIQUE_DESC technique_desc;
+ HR(d3d_effect->GetTechniqueDesc(technique, &technique_desc));
+ if (technique_desc.Passes != 1) {
+ LOG(ERROR) << "Only 1 pass is allowed in an effect.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ d3d_effect->SetTechnique(technique);
+ D3DXHANDLE pass = d3d_effect->GetPass(technique, 0);
+ D3DXPASS_DESC pass_desc;
+ HR(d3d_effect->GetPassDesc(pass, &pass_desc));
+ ID3DXConstantTable *table = NULL;
+ HR(gapi->D3DXGetShaderConstantTable(pass_desc.pPixelShaderFunction,
+ &table));
+ if (!table) {
+ LOG(ERROR) << "Could not get the constant table.";
+ d3d_effect->Release();
+ return NULL;
+ }
+ IDirect3DVertexShader9 *d3d_vertex_shader = NULL;
+ HR(device->CreateVertexShader(pass_desc.pVertexShaderFunction,
+ &d3d_vertex_shader));
+ if (!d3d_vertex_shader) {
+ d3d_effect->Release();
+ table->Release();
+ DLOG(ERROR) << "Failed to create vertex shader";
+ return NULL;
+ }
+
+ return new EffectD3D9(gapi, d3d_effect, table, d3d_vertex_shader);
+}
+
+// Begins rendering with the effect, setting all the appropriate states.
+bool EffectD3D9::Begin() {
+ UINT numpasses;
+ HR(d3d_effect_->Begin(&numpasses, 0));
+ HR(d3d_effect_->BeginPass(0));
+ sync_parameters_ = false;
+ return SetSamplers();
+}
+
+// Terminates rendering with the effect, resetting all the appropriate states.
+void EffectD3D9::End() {
+ HR(d3d_effect_->EndPass());
+ HR(d3d_effect_->End());
+}
+
+// Gets the parameter count from the D3D effect description.
+unsigned int EffectD3D9::GetParamCount() {
+ D3DXEFFECT_DESC effect_desc;
+ HR(d3d_effect_->GetDesc(&effect_desc));
+ return effect_desc.Parameters;
+}
+
+// Gets the number of input streams from the shader.
+unsigned int EffectD3D9::GetStreamCount() {
+ return streams_.size();
+}
+
+// Retrieves the matching DataType from a D3D parameter description.
+static effect_param::DataType GetDataTypeFromD3D(
+ const D3DXPARAMETER_DESC &desc) {
+ switch (desc.Type) {
+ case D3DXPT_FLOAT:
+ switch (desc.Class) {
+ case D3DXPC_SCALAR:
+ return effect_param::kFloat1;
+ case D3DXPC_VECTOR:
+ switch (desc.Columns) {
+ case 2:
+ return effect_param::kFloat2;
+ case 3:
+ return effect_param::kFloat3;
+ case 4:
+ return effect_param::kFloat4;
+ default:
+ return effect_param::kUnknown;
+ }
+ case D3DXPC_MATRIX_ROWS:
+ case D3DXPC_MATRIX_COLUMNS:
+ if (desc.Columns == 4 && desc.Rows == 4) {
+ return effect_param::kMatrix4;
+ } else {
+ return effect_param::kUnknown;
+ }
+ default:
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_INT:
+ if (desc.Class == D3DXPC_SCALAR) {
+ return effect_param::kInt;
+ } else {
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_BOOL:
+ if (desc.Class == D3DXPC_SCALAR) {
+ return effect_param::kBool;
+ } else {
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_SAMPLER:
+ case D3DXPT_SAMPLER2D:
+ case D3DXPT_SAMPLER3D:
+ case D3DXPT_SAMPLERCUBE:
+ if (desc.Class == D3DXPC_OBJECT) {
+ return effect_param::kSampler;
+ } else {
+ return effect_param::kUnknown;
+ }
+ case D3DXPT_TEXTURE:
+ case D3DXPT_TEXTURE1D:
+ case D3DXPT_TEXTURE2D:
+ case D3DXPT_TEXTURE3D:
+ case D3DXPT_TEXTURECUBE:
+ if (desc.Class == D3DXPC_OBJECT) {
+ return effect_param::kTexture;
+ } else {
+ return effect_param::kUnknown;
+ }
+ default:
+ return effect_param::kUnknown;
+ }
+}
+
+// Gets a handle to the selected parameter, and wraps it into an
+// EffectParamD3D9 if successful.
+EffectParamD3D9 *EffectD3D9::CreateParam(unsigned int index) {
+ D3DXHANDLE handle = d3d_effect_->GetParameter(NULL, index);
+ if (!handle) return NULL;
+ return EffectParamD3D9::Create(this, handle);
+}
+
+// Gets a handle to the selected parameter, and wraps it into an
+// EffectParamD3D9 if successful.
+EffectParamD3D9 *EffectD3D9::CreateParamByName(const char *name) {
+ D3DXHANDLE handle = d3d_effect_->GetParameterByName(NULL, name);
+ if (!handle) return NULL;
+ return EffectParamD3D9::Create(this, handle);
+}
+
+bool EffectD3D9::CommitParameters() {
+ if (sync_parameters_) {
+ sync_parameters_ = false;
+ d3d_effect_->CommitChanges();
+ return SetSamplers();
+ } else {
+ return true;
+ }
+}
+
+bool EffectD3D9::SetSamplers() {
+ IDirect3DDevice9 *d3d_device = gapi_->d3d_device();
+ bool result = true;
+ for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) {
+ SamplerD3D9 *sampler = gapi_->GetSampler(samplers_[i]);
+ if (sampler) {
+ result &= sampler->ApplyStates(gapi_, i);
+ } else {
+ HR(d3d_device->SetTexture(i, NULL));
+ }
+ }
+ return result;
+}
+
+bool EffectD3D9::SetStreams() {
+ if (!d3d_vertex_shader_) {
+ return false;
+ }
+ UINT size;
+ d3d_vertex_shader_->GetFunction(NULL, &size);
+ scoped_array<DWORD> function(new DWORD[size]);
+ d3d_vertex_shader_->GetFunction(function.get(), &size);
+
+ UINT num_semantics;
+ HR(gapi_->D3DXGetShaderInputSemantics(function.get(),
+ NULL,
+ &num_semantics));
+ scoped_array<D3DXSEMANTIC> semantics(new D3DXSEMANTIC[num_semantics]);
+ HR(gapi_->D3DXGetShaderInputSemantics(function.get(),
+ semantics.get(),
+ &num_semantics));
+
+ streams_.resize(num_semantics);
+ for (UINT i = 0; i < num_semantics; ++i) {
+ vertex_struct::Semantic semantic;
+ unsigned int semantic_index;
+ if (D3DSemanticToCBSemantic(static_cast<D3DDECLUSAGE>(semantics[i].Usage),
+ static_cast<int>(semantics[i].UsageIndex),
+ &semantic, &semantic_index)) {
+ streams_[i].semantic = semantic;
+ streams_[i].semantic_index = semantic_index;
+ }
+ }
+ return true;
+}
+
+void EffectD3D9::LinkParam(EffectParamD3D9 *param) {
+ params_.push_back(param);
+}
+
+void EffectD3D9::UnlinkParam(EffectParamD3D9 *param) {
+ std::remove(params_.begin(), params_.end(), param);
+}
+
+// Fills the Desc structure, appending name and semantic if any, and if enough
+// room is available in the buffer.
+bool EffectD3D9::GetStreamDesc(unsigned int index,
+ unsigned int size,
+ void *data) {
+ using effect_stream::Desc;
+ if (size < sizeof(Desc)) // NOLINT
+ return false;
+
+ Desc *desc = static_cast<Desc *>(data);
+ *desc = streams_[index];
+ return true;
+}
+
+EffectParamD3D9::EffectParamD3D9(effect_param::DataType data_type,
+ EffectD3D9 *effect,
+ D3DXHANDLE handle)
+ : EffectParam(data_type),
+ effect_(effect),
+ handle_(handle),
+ sampler_units_(NULL),
+ sampler_unit_count_(0) {
+ DCHECK(effect_);
+ effect_->LinkParam(this);
+}
+
+EffectParamD3D9::~EffectParamD3D9() {
+ if (effect_) effect_->UnlinkParam(this);
+}
+
+EffectParamD3D9 *EffectParamD3D9::Create(EffectD3D9 *effect,
+ D3DXHANDLE handle) {
+ DCHECK(effect);
+ D3DXPARAMETER_DESC desc;
+ HR(effect->d3d_effect_->GetParameterDesc(handle, &desc));
+ effect_param::DataType data_type = GetDataTypeFromD3D(desc);
+ EffectParamD3D9 *param = new EffectParamD3D9(data_type, effect, handle);
+ if (data_type == effect_param::kSampler) {
+ ID3DXConstantTable *table = effect->fs_constant_table_;
+ DCHECK(table);
+ D3DXHANDLE sampler_handle = table->GetConstantByName(NULL, desc.Name);
+ if (sampler_handle) {
+ D3DXCONSTANT_DESC desc_array[kMaxSamplerUnits];
+ unsigned int num_desc = kMaxSamplerUnits;
+ table->GetConstantDesc(sampler_handle, desc_array, &num_desc);
+ // We have no good way of querying how many descriptions would really be
+ // returned as we're capping the number to kMaxSamplerUnits (which should
+ // be more than sufficient). If however we do end up with the max number
+ // there's a chance that there were actually more so let's log it.
+ if (num_desc == kMaxSamplerUnits) {
+ DLOG(WARNING) << "Number of constant descriptions might have exceeded "
+ << "the maximum of " << kMaxSamplerUnits;
+ }
+ param->sampler_unit_count_ = 0;
+ if (num_desc > 0) {
+ param->sampler_units_.reset(new unsigned int[num_desc]);
+ for (unsigned int desc_index = 0; desc_index < num_desc; desc_index++) {
+ D3DXCONSTANT_DESC constant_desc = desc_array[desc_index];
+ if (constant_desc.Class == D3DXPC_OBJECT &&
+ (constant_desc.Type == D3DXPT_SAMPLER ||
+ constant_desc.Type == D3DXPT_SAMPLER2D ||
+ constant_desc.Type == D3DXPT_SAMPLER3D ||
+ constant_desc.Type == D3DXPT_SAMPLERCUBE)) {
+ param->sampler_units_[param->sampler_unit_count_++] =
+ constant_desc.RegisterIndex;
+ }
+ }
+ }
+ }
+ // if the sampler hasn't been found in the constant table, that means it
+ // isn't referenced, hence it doesn't use any sampler unit.
+ }
+ return param;
+}
+
+// Fills the Desc structure, appending name and semantic if any, and if enough
+// room is available in the buffer.
+bool EffectParamD3D9::GetDesc(unsigned int size, void *data) {
+ using effect_param::Desc;
+ if (size < sizeof(Desc)) // NOLINT
+ return false;
+ if (!effect_)
+ return false;
+ ID3DXEffect *d3d_effect = effect_->d3d_effect_;
+ D3DXPARAMETER_DESC d3d_desc;
+ HR(d3d_effect->GetParameterDesc(handle_, &d3d_desc));
+ unsigned int name_size =
+ d3d_desc.Name ? static_cast<unsigned int>(strlen(d3d_desc.Name)) + 1 : 0;
+ unsigned int semantic_size = d3d_desc.Semantic ?
+ static_cast<unsigned int>(strlen(d3d_desc.Semantic)) + 1 : 0;
+ unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT
+
+ Desc *desc = static_cast<Desc *>(data);
+ memset(desc, 0, sizeof(*desc));
+ desc->size = total_size;
+ desc->data_type = data_type();
+ desc->data_size = GetDataSize(data_type());
+ desc->name_offset = 0;
+ desc->name_size = name_size;
+ desc->num_elements = d3d_desc.Elements;
+ desc->semantic_offset = 0;
+ desc->semantic_size = semantic_size;
+ unsigned int current_offset = sizeof(Desc);
+ if (d3d_desc.Name && current_offset + name_size <= size) {
+ desc->name_offset = current_offset;
+ memcpy(static_cast<char *>(data) + current_offset,
+ d3d_desc.Name, name_size);
+ current_offset += name_size;
+ }
+ if (d3d_desc.Semantic && current_offset + semantic_size <= size) {
+ desc->semantic_offset = current_offset;
+ memcpy(static_cast<char *>(data) + current_offset,
+ d3d_desc.Semantic, semantic_size);
+ current_offset += semantic_size;
+ }
+ return true;
+}
+
+// Sets the data into the D3D effect parameter, using the appropriate D3D call.
+bool EffectParamD3D9::SetData(GAPID3D9 *gapi,
+ unsigned int size,
+ const void * data) {
+ if (!effect_)
+ return false;
+ ID3DXEffect *d3d_effect = effect_->d3d_effect_;
+ effect_param::DataType type = data_type();
+ if (size < effect_param::GetDataSize(type)) return false;
+ switch (type) {
+ case effect_param::kFloat1:
+ HR(d3d_effect->SetFloat(handle_, *static_cast<const float *>(data)));
+ break;
+ case effect_param::kFloat2:
+ HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
+ 2));
+ break;
+ case effect_param::kFloat3:
+ HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
+ 3));
+ break;
+ case effect_param::kFloat4:
+ HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
+ 4));
+ break;
+ case effect_param::kMatrix4:
+ HR(d3d_effect->SetMatrix(handle_,
+ reinterpret_cast<const D3DXMATRIX *>(data)));
+ break;
+ case effect_param::kInt:
+ HR(d3d_effect->SetInt(handle_, *static_cast<const int *>(data)));
+ break;
+ case effect_param::kBool:
+ HR(d3d_effect->SetBool(handle_, *static_cast<const bool *>(data)?1:0));
+ break;
+ case effect_param::kSampler: {
+ ResourceId id = *static_cast<const ResourceId *>(data);
+ for (unsigned int i = 0; i < sampler_unit_count_; ++i) {
+ effect_->samplers_[sampler_units_[i]] = id;
+ }
+ break;
+ }
+ case effect_param::kTexture: {
+ // TODO(rlp): finish
+ break;
+ }
+ default:
+ DLOG(ERROR) << "Invalid parameter type.";
+ return false;
+ }
+ if (effect_ == gapi->current_effect()) {
+ effect_->sync_parameters_ = true;
+ }
+ return true;
+}
+
+// Calls EffectD3D9::Create, and assign the result to the resource ID.
+// If changing the current effect, dirty it.
+parse_error::ParseError GAPID3D9::CreateEffect(
+ ResourceId id,
+ unsigned int size,
+ const void *data) {
+ if (id == current_effect_id_) DirtyEffect();
+ // Even though Assign would Destroy the effect at id, we do it explicitly in
+ // case the creation fails.
+ effects_.Destroy(id);
+ // Data is vp_main \0 fp_main \0 effect_text.
+ String vertex_program_entry;
+ String fragment_program_entry;
+ String effect_code;
+ if (!ParseEffectData(size, data,
+ &vertex_program_entry,
+ &fragment_program_entry,
+ &effect_code)) {
+ return parse_error::kParseInvalidArguments;
+ }
+ EffectD3D9 * effect = EffectD3D9::Create(this, effect_code,
+ vertex_program_entry,
+ fragment_program_entry);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ effects_.Assign(id, effect);
+ return parse_error::kParseNoError;
+}
+
+// Destroys the Effect resource.
+// If destroying the current effect, dirty it.
+parse_error::ParseError GAPID3D9::DestroyEffect(ResourceId id) {
+ if (id == current_effect_id_) DirtyEffect();
+ return effects_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Sets the current effect ID, dirtying the current effect.
+parse_error::ParseError GAPID3D9::SetEffect(ResourceId id) {
+ DirtyEffect();
+ current_effect_id_ = id;
+ return parse_error::kParseNoError;
+}
+
+// Gets the param count from the effect and store it in the memory buffer.
+parse_error::ParseError GAPID3D9::GetParamCount(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectD3D9 *effect = effects_.Get(id);
+ if (!effect || size < sizeof(Uint32)) // NOLINT
+ return parse_error::kParseInvalidArguments;
+ *static_cast<Uint32 *>(data) = effect->GetParamCount();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::CreateParam(
+ ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int index) {
+ EffectD3D9 *effect = effects_.Get(effect_id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ EffectParamD3D9 *param = effect->CreateParam(index);
+ if (!param) return parse_error::kParseInvalidArguments;
+ effect_params_.Assign(param_id, param);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::CreateParamByName(
+ ResourceId param_id,
+ ResourceId effect_id,
+ unsigned int size,
+ const void *name) {
+ EffectD3D9 *effect = effects_.Get(effect_id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ std::string string_name(static_cast<const char *>(name), size);
+ EffectParamD3D9 *param = effect->CreateParamByName(string_name.c_str());
+ if (!param) return parse_error::kParseInvalidArguments;
+ effect_params_.Assign(param_id, param);
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::DestroyParam(ResourceId id) {
+ return effect_params_.Destroy(id) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::SetParamData(
+ ResourceId id,
+ unsigned int size,
+ const void *data) {
+ EffectParamD3D9 *param = effect_params_.Get(id);
+ if (!param) return parse_error::kParseInvalidArguments;
+ return param->SetData(this, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+parse_error::ParseError GAPID3D9::GetParamDesc(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectParamD3D9 *param = effect_params_.Get(id);
+ if (!param) return parse_error::kParseInvalidArguments;
+ return param->GetDesc(size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+// Gets the stream count from the effect and stores it in the memory buffer.
+parse_error::ParseError GAPID3D9::GetStreamCount(
+ ResourceId id,
+ unsigned int size,
+ void *data) {
+ EffectD3D9 *effect = effects_.Get(id);
+ if (!effect || size < sizeof(Uint32)) // NOLINT
+ return parse_error::kParseInvalidArguments;
+ *static_cast<Uint32 *>(data) = effect->GetStreamCount();
+ return parse_error::kParseNoError;
+}
+
+parse_error::ParseError GAPID3D9::GetStreamDesc(
+ ResourceId id,
+ unsigned int index,
+ unsigned int size,
+ void *data) {
+ EffectD3D9 *effect = effects_.Get(id);
+ if (!effect) return parse_error::kParseInvalidArguments;
+ return effect->GetStreamDesc(index, size, data) ?
+ parse_error::kParseNoError :
+ parse_error::kParseInvalidArguments;
+}
+
+
+// If the current effect is valid, call End on it, and tag for revalidation.
+void GAPID3D9::DirtyEffect() {
+ if (validate_effect_) return;
+ DCHECK(current_effect_);
+ current_effect_->End();
+ current_effect_ = NULL;
+ validate_effect_ = true;
+}
+
+// Gets the current effect, and calls Begin on it (if successful).
+// Should only be called if the current effect is not valid.
+bool GAPID3D9::ValidateEffect() {
+ DCHECK(validate_effect_);
+ DCHECK(!current_effect_);
+ current_effect_ = effects_.Get(current_effect_id_);
+ if (!current_effect_) return false;
+ validate_effect_ = false;
+ return current_effect_->Begin();
+}
+
+} // namespace o3d
+} // namespace command_buffer