Fail to draw multiple geometric shapes

Started by
3 comments, last by leonard2012 12 years ago
I am new to Direct3D programming and now an issue has driven me nuts. What I want to do is to draw multiple user selected geometric shapes (lines, triangles, polygons) in the client window. My implementation is attatched at the end of this post. In the code, there is a macro USE_DYNAMIC_BUFFER. Defining this macro will enable D3D dynamic vertex buffer, undefining it will use D3D static vertex buffer. My code will crash the display driver when static vertex buffer is used. When dynamic vertex buffer is used, the performance is so poor so that the rendering process looks like animation.
Some explanation of my code.The function mgral_directx::draw will be called once for each shape whenever the client area needs to be updated (i.e. the applciation receives an WM_PAINT message). The function arguments points and count store the vertex positions of the shape and number of vertices. They vary for each shape. An variable is the type ID3D10Buffer is declared as static as it can only be created only once.
I am looking forward to your kindly help, thanks in advance.


#define USE_DYNAMIC_BUFFER 1
void mgral_directx::draw(int obj_type, mpoint *points, int count)
{
static ID3D10Buffer* iD3dVB=NULL;
std::vector<Vertex> vertices(count);
Vertex* v = 0;
// Assign values to vertex buffer
#ifndef USE_DYNAMIC_BUFFER
for ( int i = 0; i < count; i++ ) {
vertices.pos = D3DXVECTOR3(points.x, points.y, points.z);
vertices.color = D3DXCOLOR(penColor_);
}
#endif

// Create vertex buffer
if ( iD3dVB==NULL ) {
D3D10_BUFFER_DESC vbd;
#ifndef USE_DYNAMIC_BUFFER
vbd.Usage = D3D10_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(Vertex) * count;
vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &vertices[0];
HR(iD3dDevice_->CreateBuffer(&vbd, &vinitData, &iD3dVB));
#else
vbd.Usage = D3D10_USAGE_DYNAMIC;
vbd.ByteWidth = sizeof(Vertex) * count;
vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
vbd.MiscFlags = 0;
HR(iD3dDevice_->CreateBuffer(&vbd, 0, &iD3dVB));
#endif
// Create effect
buildFX();
// Create input layout
buildVertexLayouts();
}
// Update vertex buffer
#ifdef USE_DYNAMIC_BUFFER
HR(iD3dVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&v ));
for ( int i = 0; i < count; i++ ) {
v.pos = D3DXVECTOR3(points.x, points.y, points.z);
v.color = D3DXCOLOR(penColor_);
}
iD3dVB->Unmap();
#endif
// Restore default states, input layout and primitive topology
// because iD3dxFont_->DrawText changes them. Note that we can
// restore the default states by passing null.
iD3dDevice_->OMSetDepthStencilState(0, 0);
float blendFactors[] = {0.0f, 0.0f, 0.0f, 0.0f};
iD3dDevice_->OMSetBlendState(0, blendFactors, 0xffffffff);
// Bind the input layout to the device
iD3dDevice_->IASetInputLayout(mVertexLayout);
// Specify the primitive topology
iD3dDevice_->IASetPrimitiveTopology(d3dPrimitiveTopologies[obj_type]);
// Bind vertex buffer to the input slot of the device
UINT stride = sizeof(Vertex);
UINT offset = 0;
iD3dDevice_->IASetVertexBuffers(0, 1, &iD3dVB, &stride, &offset);
// set constants
D3DXMATRIX mWVP = modelMatrix_*viewMatrix_*projectMatrix_;
mfxWVPVar->SetMatrix((float*)&mWVP);
// Draw the geometry objects
D3D10_TECHNIQUE_DESC techDesc;
mTech->GetDesc( &techDesc );
for(UINT p = 0; p < techDesc.Passes; ++p) {
mTech->GetPassByIndex( p )->Apply(0);
iD3dDevice_->Draw(count, 0);
}
// Remember to add the line below after all drawing code.
iDxgiSwapChain_->Present(0, 0);
//ReleaseCOM(iD3dVB);
}
void mgral_directx::buildFX()
{
DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
shaderFlags |= D3D10_SHADER_DEBUG;
shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;
#endif

ID3D10Blob* compilationErrors = 0;
HRESULT hr = 0;
hr = D3DX10CreateEffectFromFile(TEXT("shader.fxo"), 0, 0,
"fx_4_0", shaderFlags, 0, iD3dDevice_, 0, 0, &mFX, &compilationErrors, 0);
if(FAILED(hr)) {
if( compilationErrors ) {
MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0);
ReleaseCOM(compilationErrors);
}
DXTrace(__FILE__, (DWORD)__LINE__, hr, TEXT("D3DX10CreateEffectFromFile"), true);
}
mTech = mFX->GetTechniqueByName("ColorTech");
mfxWVPVar = mFX->GetVariableByName("gWVP")->AsMatrix();
}
void mgral_directx::buildVertexLayouts()
{
// Create the vertex input layout.
D3D10_INPUT_ELEMENT_DESC vertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0}
};
// Create the input layout
D3D10_PASS_DESC PassDesc;
mTech->GetPassByIndex(0)->GetDesc(&PassDesc);
HR(iD3dDevice_->CreateInputLayout(vertexDesc, 2, PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize, &mVertexLayout));
}
Advertisement
You should try to only create buffers at initialization time. If you have to update the data in the buffers, you need to use map/unmap with a dynamic buffer, or updatesubresource with a default buffer. an immutable buffer cannot be updated or even accessed by the CPU, so you have to make sure that you put everything in an immutable buffer right when you create it, otherwise, you won't be able to access after it's created. in fact, the only accessing of an immutable buffer is the ability to read it by the gpu. neither the gpu or cpu can write to an immutable buffer after it's created.

generally, you will want to use a dynamic buffer if you are going to be updating it once or more per frame, and a default buffer if you will be updating it less than once per frame (not updating it every frame)
Thank you for your help, iedoc.
Actually I am writing an graphics editing desktop application that use D3D for rendering graphical objects (lines, polygons). And my application window is only updated when necessary, and it is not updated periodically by a timer. So my application does not follow the initialization-update-draw cycle that a game adopts.
I don't know what you refer to as "a default buffer" mean. As you can see from my code, when the macro USE_DYNAMIC_BUFFER is defined, a dynamic buffer is indeed used. This agrees with your advice. Contrary to a game, where the buffer content is a function of time, in my case, the buffer content is a function of geometric shapes. That is the buffer content is changed for different geometric shapes. If I create buffer outside the draw routine, I will have to create as many buffers as geometric shapes and have to maintain these buffers. Is this necessary? I'm looking forward for your further help.
ooh, i see what you mean, that makes sense.

when i say default buffer, that's because there are four buffer types; dynamic, immutable, default, and staging.

I guess right now all i can mention is that when you are accessing the dynamic buffer from the cpu to update it, if you do this at the wrong time, the gpu has to wait for the cpu to let go of the buffer before it can read from it and draw it's contents. I don't really know if this would help or not, but you could try it. maybe you could try to create and update the dynamic buffer the frame before you draw it. so, when calling this function, if the buffer is not created, then do not draw it's contents this current frame, and then after you do end up drawing the buffer's contents, update the buffer after you draw it.

About immutable not working, i still don't know why this might happen, but you could simply just try using a default buffer instead (D3D10_USAGE_DEFAULT)

I know this might not solve your problems, but i thought it was worth mentioning just in case

just to be more clear about updating a dynamic buffer (same goes for updating a default buffer), when you "map" the dynamic buffer on the cpu, only the cpu has access to it, so, if the GPU is waiting to read from the buffer, then it will have to wait for the cpu to let go (unmap) of the buffer. if you map the buffer at the wrong time, it will cause the gpu to sit in an idle state while it waits for the cpu to let go of the buffer, wasting valuable time on the gpu while it could be doing something else. It goes the other way around to, so that the cpu might have to wait for the gpu to stop reading from the buffer if it needs access to it.
Thank you very much for your further help, iedoc.
after I uncomment the line
//ReleaseCOM(iD3dVB);
both immutable and dynamic buffer method work.
Now the problem is the rendering process is too slow, it is noticably slower than GDI draw by eyes, even if I change the configuration from debug to release.

This topic is closed to new replies.

Advertisement