简体   繁体   中英

DirectX11 IASetVertexBuffers “ID3D11Buffer*” is incompatible with

A problem with returning a pointer from a class

I am making a project for a 3D course that involves utilizing DirectX 11. In assignments that were much smaller in scope we were encouraged to just put all the code in and around the main-file. For this project I wanted more structure, so I decided to subdivide the code into three classes: WindowHandler, D3DHandler and PipelineHandler.

D3DHandler sits in WindowHandler, and PipelineHandler sits in D3DHandler like so:

class WindowHandler
{
private:
HWND window;
MSG message

class D3DHandler()
      {
      private:
      ID3D11Device*;
      ID3D11DeviceContext*;
      IDXGISwapChain*;
      ID3D11RenderTargetView*;
      ID3D11Texture2D*;
      ID3D11DepthStencilView*;
      D3D11_VIEWPORT;

      class PipelineHandler()
            {
            private:
            ID3D11VertexShader* vShader;
            ID3D11PixelShader* pShader;
            ID3D11InputLayout* inputLayout;
            ID3D11Buffer* vertexBuffer;
            }
      } 
}

(The classes are divided into their own.h libraries, I just wanted to compress the code a bit)

Everything ran smoothly until I tried to bind my VertexBuffer in my Render() function.

void D3DHandler::Render()
{
float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    
this->immediateContext->ClearRenderTargetView(this->rtv, clearColor); //Clear backbuffer
this->immediateContext->ClearDepthStencilView(this->dsView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

UINT32 vertexSize = sizeof(Vertex); //Will be the size of 8 floats, x y z, r g b, u v
UINT32 offset = 0;

this->immediateContext->VSSetShader(this->ph.GetVertexShader(), nullptr, 0);
this->immediateContext->IASetVertexBuffers(0, 1, this->ph.GetVertexBuffer(), &vertexSize, &offset);
this->immediateContext->IASetInputLayout(this->ph.GetInputLayout());
this->immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
this->immediateContext->PSSetShader(this->ph.GetPixelShader(), nullptr, 0);
//
// Draw geometry
this->immediateContext->Draw(3, 0);
}

The problem occurs at IASetVertexBuffers , where this->ph.GetVertexBuffer() gives the error

"ID3D11Buffer*" is incomaptible with parameter of type "ID3D11Buffer *const *"

The Get-function in PipelineHandler returns a pointer to the COM object, and for VertexBuffer it looks like this:

ID3D11Buffer * PipelineHandler::GetVertexBuffer() const
{
   return this->vertexBuffer;
}

From what documentation I've found, IASetVertexBuffers expects an array of buffers, so a double pointer. However, in the code I've worked with before, where the ID3D11Buffer * has been global, the same code generated no errors (and yes, most of the code I'm working so far has been wholesale copied from the last assignment in this course, just placed into classes).

I have tried to:

  • to remove the this-> pointer in front of the ph
  • Creating a new function called ID3D11Buffer & GetVertexBufferRef() const which returns return *this->vertexBuffer; using that instead.

I yet to try:

  • Moving vertexBuffer from the PipelineHandler and up to D3DHandler. I have a feeling that would work, but it would also disconnect the vertex buffer from the other objects that I deem to be part of the pipeline and not the context, which is something I would like to avoid.

I am grateful for any feedback I can get. I'm fairly new to programming, so any comments that aren't a solution to my problem are just as welcome.

The problem your are having is that this function signature does not take a ID3D11Buffer* interface pointer. It takes an array of ID3D11Buffer* interface pointers.

this->immediateContext->IASetVertexBuffers(0, 1, this->ph.GetVertexBuffer(), &vertexSize, &offset);

Can be any of the following:

this->immediateContext->IASetVertexBuffers(0, 1, &this->ph.GetVertexBuffer(), &vertexSize, &offset);

-or-

ID3D11Buffer* vb = this->ph.GetVertexBuffer();
this->immediateContext->IASetVertexBuffers(0, 1, &vb, &vertexSize, &offset);

-or-

ID3D11Buffer* vb[] = { this->ph.GetVertexBuffer() };
this->immediateContext->IASetVertexBuffers(0, 1, vb, &vertexSize, &offset);

This is because the Direct3D 11 API supports 'multi-stream' rendering where you have more than one Vertex Buffer referenced in the Input Layout which is merged as it is drawn. The function also takes an array of vertex sizes and offsets, which is why you had to take the address of the values vertexSize and offset instead of just passing by value. See Microsoft Docs for full details on the function signature.

This feature was first introduced back in Direct3D 9, so the best introduction to it is found here . With Direct3D 11, depending on Direct3D hardware feature level you can use up to 16 or 32 slots at once. That said, most basic rendering uses a single stream/VertexBuffer.

  1. You should take a look at this page as to why the 'first' option above can get you into trouble with smart-pointers.

  2. For the 'second' option, I'd recommend using C++11's auto keyboard so it would be: auto vb = this->ph.GetVertexBuffer();

  3. The 'third' option obviously makes most sense if you are using more than one VertexBuffer for multi-stream rendering.

Note that you can never have more than one ID3D11Buffer active for the Index Buffer, so the function signature does in fact take a ID3D11Buffer* in that case and not an array. See Microsoft Docs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM