0

Adding GetStreamInfo functionality (and passing corresponding unit test).

Review URL: http://codereview.chromium.org/147237

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19859 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
rlp@google.com
2009-07-02 23:28:00 +00:00
parent dcdae9eeab
commit ac300913de
13 changed files with 384 additions and 5 deletions

@ -207,5 +207,68 @@ void EffectHelper::DestroyEffectParameters(
}
}
bool EffectHelper::GetEffectStreams(ResourceID effect_id,
std::vector<EffectStreamDesc> *descs) {
using effect_stream::Desc;
DCHECK_NE(effect_id, kInvalidResource);
// Get the param count.
Uint32 *retval = shm_allocator_->AllocTyped<Uint32>(1);
CommandBufferEntry args[5];
args[0].value_uint32 = effect_id;
args[1].value_uint32 = sizeof(*retval);
args[2].value_uint32 = shm_id_;
args[3].value_uint32 = shm_allocator_->GetOffset(retval);
helper_->AddCommand(GET_STREAM_COUNT, 4, args);
// Finish has to be called to get the result.
helper_->Finish();
// We could have failed if the effect_id is invalid.
if (helper_->interface()->GetParseError() !=
BufferSyncInterface::PARSE_NO_ERROR) {
shm_allocator_->Free(retval);
return false;
}
unsigned int stream_count = *retval;
shm_allocator_->Free(retval);
unsigned int max_buffer_size = shm_allocator_->GetLargestFreeOrPendingSize();
if (max_buffer_size < sizeof(Desc)) { // NOLINT
// Not enough memory to get at least 1 stream desc.
return false;
}
descs->resize(stream_count);
// Read stream descriptions in batches. We use as much shared memory as
// possible so that we only call Finish as little as possible.
unsigned int max_stream_per_batch =
std::min(stream_count, max_buffer_size / sizeof(Desc)); // NOLINT
Desc *raw_descs = shm_allocator_->AllocTyped<Desc>(max_stream_per_batch);
DCHECK(raw_descs);
for (unsigned int i = 0; i < stream_count; i += max_stream_per_batch) {
unsigned int count = std::min(stream_count - i, max_stream_per_batch);
for (unsigned int j = 0 ; j < count; ++j) {
EffectStreamDesc *desc = &((*descs)[i + j]);
Desc *raw_desc = raw_descs + j;
args[0].value_uint32 = effect_id;
args[1].value_uint32 = i+j;
args[2].value_uint32 = sizeof(*raw_desc);
args[3].value_uint32 = shm_id_;
args[4].value_uint32 = shm_allocator_->GetOffset(raw_desc);
helper_->AddCommand(GET_STREAM_DESC, 5, args);
}
// Finish to get the results.
helper_->Finish();
DCHECK_EQ(helper_->interface()->GetParseError(),
BufferSyncInterface::PARSE_NO_ERROR);
for (unsigned int j = 0 ; j < count; ++j) {
EffectStreamDesc *desc = &((*descs)[i + j]);
Desc *raw_desc = raw_descs + j;
desc->semantic = static_cast<vertex_struct::Semantic>(raw_desc->semantic);
desc->semantic_index = raw_desc->semantic_index;
}
}
shm_allocator_->Free(raw_descs);
return true;
}
} // namespace command_buffer
} // namespace o3d

@ -59,6 +59,10 @@ class EffectHelper {
// structure (counting strings) for a
// param.
};
struct EffectStreamDesc {
vertex_struct::Semantic semantic; // The semantic enum type.
unsigned int semantic_index;
};
EffectHelper(CommandBufferHelper *helper,
FencedAllocatorWrapper *shm_allocator,
@ -119,6 +123,23 @@ class EffectHelper {
// descs: the vector of descriptions containing the ResourceIDs of the
// parameters to destroy.
void DestroyEffectParameters(const std::vector<EffectParamDesc> &descs);
// Gets all the input stream semantics and semantic indices in an
// array. These will be retrieved as many as possible at a time. At least
// sizeof(effect_param::Desc) must be available for this function to succeed.
// This function will call Finish(), hence will block.
//
// Parameters:
// effect_id: the ResourceID of the effect.
// descs: A pointer to a vector containing the returned descriptions.
// The pointed vector will be cleared.
// Returns:
// true if successful. Reasons for failure are:
// - invalid effect_id,
// - not enough memory in the shm_allocator_.
bool GetEffectStreams(ResourceID effect_id,
std::vector<EffectStreamDesc> *descs);
private:
CommandBufferHelper *helper_;
FencedAllocatorWrapper *shm_allocator_;

@ -293,6 +293,8 @@ enum CommandId {
SET_PARAM_DATA, // SetParamData, 4 args
SET_PARAM_DATA_IMMEDIATE, // SetParamData, 2 args + data
GET_PARAM_DESC, // GetParamDesc, 4 args
GET_STREAM_COUNT, // GetStreamCount, 4 args.
GET_STREAM_DESC, // GetStreamDesc, 5 args
DESTROY_TEXTURE, // DestroyTexture, 1 arg
CREATE_TEXTURE_2D, // CreateTexture2D, 3 args
CREATE_TEXTURE_3D, // CreateTexture3D, 4 args

@ -481,6 +481,34 @@ class GAPIInterface {
unsigned int size,
void *data) = 0;
// Gets the number of input streams for an effect, returning it in a memory
// buffer as a Uint32.
// Parameters:
// id: the resource ID of the effect.
// size: the size of the data buffer. Must be at least 4 (the size of the
// Uint32).
// data: the buffer receiving the data.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError GetStreamCount(ResourceID id,
unsigned int size,
void *data) = 0;
// Gets the stream semantics, storing them in the data buffer. The stream
// is described by an effect_stream::Desc structure which contains a
// semantic type and a semantic index.
// Parameters:
// id: the resource ID of the effect.
// index: which stream semantic to get
// size: the size of the data buffer. Must be at least 8 (the size of two
// Uint32).
// data: the buffer receiving the data.
virtual ParseError GetStreamDesc(ResourceID id,
unsigned int index,
unsigned int size,
void *data) = 0;
// Creates a 2D texture resource.
// Parameters:
// id: the resource ID of the texture.

@ -134,6 +134,13 @@ struct Desc {
};
} // namespace effect_param
namespace effect_stream {
struct Desc {
Uint32 semantic; // the semantic type
Uint32 semantic_index;
};
} // namespace effect_stream
namespace texture {
// Texture flags.
enum Flags {

@ -367,6 +367,31 @@ BufferSyncInterface::ParseError GAPIDecoder::DoCommand(
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case GET_STREAM_COUNT:
if (arg_count == 4) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
void *data = GetAddressAndCheckSize(args[2].value_uint32,
args[3].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetStreamCount(id, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case GET_STREAM_DESC:
if (arg_count == 5) {
ResourceID id = args[0].value_uint32;
unsigned int index = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
void *data = GetAddressAndCheckSize(args[3].value_uint32,
args[4].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetStreamDesc(id, index, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_TEXTURE:
if (arg_count == 1) {
return gapi_->DestroyTexture(args[0].value_uint32);

@ -153,6 +153,13 @@ class EffectParam: public Resource {
DISALLOW_COPY_AND_ASSIGN(EffectParam);
};
class EffectStream: public Resource {
public:
explicit EffectStream() {}
private:
DISALLOW_COPY_AND_ASSIGN(EffectStream);
};
// Texture class, representing a texture resource.
class Texture: public Resource {
public:

@ -96,6 +96,59 @@ inline D3DCOLOR RGBAToD3DCOLOR(const RGBA &color) {
FloatToClampedByte(color.alpha));
}
inline bool VerifyHResult(HRESULT hr, const char* file, int line,
const char* call) {
if (FAILED(hr)) {
DLOG(ERROR) << "DX Error in file " << file
<< " line " << line << L": "
<< DXGetErrorStringA(hr) << L": " << call;
return false;
}
return true;
}
static bool D3DSemanticToCBSemantic(
D3DDECLUSAGE semantic,
unsigned int semantic_index,
vertex_struct::Semantic *out_semantic,
unsigned int *out_semantic_index) {
// TODO: what meaning do we really want to put to our semantics ? How
// do they match the semantics that are set in the effect ? What combination
// of (semantic, index) are supposed to work ?
switch (semantic) {
case D3DDECLUSAGE_POSITION:
if (semantic_index != 0) return false;
*out_semantic = vertex_struct::POSITION;
*out_semantic_index = 0;
return true;
case D3DDECLUSAGE_NORMAL:
if (semantic_index != 0) return false;
*out_semantic = vertex_struct::NORMAL;
*out_semantic_index = 0;
return true;
case D3DDECLUSAGE_TANGENT:
if (semantic_index != 0) return false;
*out_semantic = vertex_struct::TEX_COORD;
*out_semantic_index = 6;
return true;
case D3DDECLUSAGE_BINORMAL:
if (semantic_index != 0) return false;
*out_semantic = vertex_struct::TEX_COORD;
*out_semantic_index = 7;
return true;
case D3DDECLUSAGE_COLOR:
if (semantic_index > 1) return false;
*out_semantic = vertex_struct::COLOR;
*out_semantic_index = semantic_index;
return true;
case D3DDECLUSAGE_TEXCOORD:
*out_semantic = vertex_struct::TEX_COORD;
*out_semantic_index = semantic_index;
return true;
default:
return false;
}
}
} // namespace command_buffer
} // namespace o3d

@ -69,13 +69,16 @@ static void LogFXError(LPD3DXBUFFER error_buffer) {
}
EffectD3D9::EffectD3D9(ID3DXEffect *d3d_effect,
ID3DXConstantTable *fs_constant_table)
ID3DXConstantTable *fs_constant_table,
IDirect3DVertexShader9 *d3d_vertex_shader)
: 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() {
@ -86,6 +89,8 @@ EffectD3D9::~EffectD3D9() {
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
@ -152,7 +157,17 @@ EffectD3D9 *EffectD3D9::Create(GAPID3D9 *gapi,
d3d_effect->Release();
return NULL;
}
return new EffectD3D9(d3d_effect, table);
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(d3d_effect, table, d3d_vertex_shader);
}
// Begins rendering with the effect, setting all the appropriate states.
@ -177,6 +192,11 @@ unsigned int EffectD3D9::GetParamCount() {
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) {
@ -282,6 +302,38 @@ bool EffectD3D9::SetSamplers(GAPID3D9 *gapi) {
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(D3DXGetShaderInputSemantics(function.get(),
NULL,
&num_semantics));
scoped_array<D3DXSEMANTIC> semantics(new D3DXSEMANTIC[num_semantics]);
HR(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);
}
@ -290,6 +342,23 @@ 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 stream = streams_[index];
Desc *desc = static_cast<Desc *>(data);
memset(desc, 0, sizeof(*desc));
desc->semantic = stream.semantic;
desc->semantic_index = stream.semantic_index;
return true;
}
EffectParamD3D9::EffectParamD3D9(effect_param::DataType data_type,
EffectD3D9 *effect,
D3DXHANDLE handle)
@ -559,6 +628,31 @@ BufferSyncInterface::ParseError GAPID3D9::GetParamDesc(
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// Gets the stream count from the effect and store it in the memory buffer.
BufferSyncInterface::ParseError GAPID3D9::GetStreamCount(
ResourceID id,
unsigned int size,
void *data) {
EffectD3D9 *effect = effects_.Get(id);
if (!effect || size < sizeof(Uint32)) // NOLINT
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
*static_cast<Uint32 *>(data) = effect->GetStreamCount();
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPID3D9::GetStreamDesc(
ResourceID id,
unsigned int index,
unsigned int size,
void *data) {
EffectD3D9 *effect = effects_.Get(id);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return effect->GetStreamDesc(index, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// If the current effect is valid, call End on it, and tag for revalidation.
void GAPID3D9::DirtyEffect() {
if (validate_effect_) return;

@ -80,7 +80,8 @@ class EffectParamD3D9: public EffectParam {
class EffectD3D9 : public Effect {
public:
EffectD3D9(ID3DXEffect *d3d_effect,
ID3DXConstantTable *fs_constant_table);
ID3DXConstantTable *fs_constant_table,
IDirect3DVertexShader9 *d3d_vertex_shader);
virtual ~EffectD3D9();
// Compiles and creates an effect from source code.
static EffectD3D9 *Create(GAPID3D9 *gapi,
@ -101,8 +102,13 @@ class EffectD3D9 : public Effect {
EffectParamD3D9 *CreateParam(unsigned int index);
// Creates an effect parameter of the specified name.
EffectParamD3D9 *CreateParamByName(const char *name);
// Gets the number of stream inputs for the effect.
unsigned int GetStreamCount();
// Gets the stream data with the specified index.
bool GetStreamDesc(unsigned int index, unsigned int size, void *data);
private:
typedef std::vector<EffectParamD3D9 *> ParamList;
typedef std::vector<effect_stream::Desc> StreamList;
// Links a param into this effect.
void LinkParam(EffectParamD3D9 *param);
@ -110,14 +116,19 @@ class EffectD3D9 : public Effect {
void UnlinkParam(EffectParamD3D9 *param);
// Sets sampler states.
bool SetSamplers(GAPID3D9 *gapi);
// Sets streams vector.
bool SetStreams();
ID3DXEffect *d3d_effect_;
IDirect3DVertexShader9 *d3d_vertex_shader_;
ID3DXConstantTable *fs_constant_table_;
ParamList params_;
StreamList streams_;
bool sync_parameters_;
ResourceID samplers_[kMaxSamplerUnits];
friend class EffectParamD3D9;
friend class EffectStreamD3D9;
DISALLOW_COPY_AND_ASSIGN(EffectD3D9);
};

@ -195,6 +195,17 @@ class GAPID3D9 : public GAPIInterface {
unsigned int size,
void *data);
// Implements the GetStreamCount function for D3D9.
virtual ParseError GetStreamCount(ResourceID id,
unsigned int size,
void *data);
// Implements the GetStreamDesc function for D3D9.
virtual ParseError GetStreamDesc(ResourceID id,
unsigned int index,
unsigned int size,
void *data);
// Implements the CreateTexture2D function for D3D9.
virtual ParseError CreateTexture2D(ResourceID id,
unsigned int width,

@ -49,6 +49,7 @@ using command_buffer::CommandBufferEntry;
using command_buffer::CommandBufferHelper;
using command_buffer::ResourceID;
namespace effect_param = command_buffer::effect_param;
namespace vertex_struct = command_buffer::vertex_struct;
EffectCB::EffectCB(ServiceLocator *service_locator, RendererCB *renderer)
: Effect(service_locator),
@ -125,6 +126,11 @@ bool EffectCB::LoadFromFXString(const String& source) {
return false;
}
}
if (!effect_helper.GetEffectStreams(resource_id, &stream_descs_)) {
O3D_ERROR(service_locator()) << "Failed to get streams.";
Destroy();
return false;
}
set_source(source);
return true;
}
@ -200,8 +206,59 @@ void EffectCB::GetParameterInfo(EffectParameterInfoArray *array) {
}
}
static bool CBSemanticToO3DSemantic(
vertex_struct::Semantic semantic,
unsigned int semantic_index,
Stream::Semantic *out_semantic,
unsigned int *out_semantic_index) {
switch (semantic) {
case vertex_struct::POSITION:
if (semantic_index != 0) return false;
*out_semantic = Stream::POSITION;
*out_semantic_index = 0;
return true;
case vertex_struct::NORMAL:
if (semantic_index != 0) return false;
*out_semantic = Stream::NORMAL;
*out_semantic_index = 0;
return true;
case vertex_struct::COLOR:
if (semantic_index > 1) return false;
*out_semantic = Stream::COLOR;
*out_semantic_index = semantic_index;
return true;
case vertex_struct::TEX_COORD:
if (semantic_index == 6) {
*out_semantic = Stream::TANGENT;
*out_semantic_index = 0;
return true;
} else if (semantic_index == 7) {
*out_semantic = Stream::BINORMAL;
*out_semantic_index = 0;
return true;
} else {
*out_semantic = Stream::TEXCOORD;
*out_semantic_index = semantic_index;
return true;
}
default:
return false;
}
}
void EffectCB::GetStreamInfo(EffectStreamInfoArray *array) {
// TODO(rlp)
DCHECK(array);
array->clear();
for (unsigned int i = 0; i < stream_descs_.size(); ++i) {
Stream::Semantic semantic;
unsigned int semantic_index;
if (CBSemanticToO3DSemantic(stream_descs_[i].semantic,
stream_descs_[i].semantic_index,
&semantic,
&semantic_index)) {
array->push_back(EffectStreamInfo(semantic, semantic_index));
}
}
}
} // namespace o3d

@ -75,9 +75,9 @@ class EffectCB : public Effect {
// The command buffer resource ID for the effect.
command_buffer::ResourceID resource_id_;
std::vector<EffectHelper::EffectParamDesc> param_descs_;
std::vector<EffectHelper::EffectStreamDesc> stream_descs_;
// A generation counter to dirty ParamCacheCBs.
unsigned int generation_;
// The renderer that created this effect.
RendererCB *renderer_;
DISALLOW_IMPLICIT_CONSTRUCTORS(EffectCB);