简体   繁体   English

C++ [D3D11] - 奇怪的行为,函数被调用了 2 次

[英]C++ [D3D11] - Weird behavior, function is called 2 times

THE SCENE:现场:
So, I have been learning D3D11 programming for the last 15 days now using "3d game programming with DirectX11" book by Frank Luna.因此,在过去的 15 天里,我一直在使用 Frank Luna 所著的“使用 DirectX11 进行 3d 游戏编程”一书来学习 D3D11 编程。 I had done pretty well upto now.到目前为止,我已经做得很好了。 But because the book uses a deprecated D3DX11 library, I had to devise my own functions as replacement.但是因为这本书使用了一个不推荐使用的 D3DX11 库,我不得不设计自己的函数作为替代。

One of it is a function to compile shaders.其中之一是编译着色器的函数。 It is like this-是这样的——
Helpers.cpp Helpers.cpp

#include "Helpers.h"


HRESULT CompileShader(LPCWSTR srcFile, LPCSTR entryPoint, LPCSTR profile, ID3DBlob** blob)
{
    if(!srcFile || !entryPoint || !profile || !blob)
        return E_INVALIDARG;

    *blob = nullptr;

    UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined(DEBUG) || defined(_DEBUG)
    flags |= D3DCOMPILE_DEBUG;
#endif

    ComPtr<ID3DBlob> errorBlob;

    HRESULT hr = D3DCompileFromFile(
        srcFile, nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, 
        entryPoint, profile, flags, 0, &blob, errorBlob.GetAddressOf());

    if(errorBlob.Get())
    {
        MessageBoxA(0, (char*)errorBlob->GetBufferPointer(), "Shader ERROR/WARNING", MB_ICONINFORMATION);
        errorBlob.Reset();
    }

    if(FAILED(hr))
    {
        (*blob)->Release();

        std::wostringstream ss;
        ss << L"Error in compiling shader: " << srcFile;
        MessageBox(0, ss.str().c_str(), L"ERROR", MB_ICONERROR);

        return hr;
    }

    return hr;
}

NOTE: The file Helpers.h includes nothing but this function declaration and some includes.注意:文件 Helpers.h 只包含这个函数声明和一些包含。



Some other helper functions/defines are:-其他一些辅助函数/定义是:-

  1. Framework for D3D11 base code :- D3D11 基本代码框架:-
    In D3DApp.hD3DApp.h

     class D3DApp { protected: //Win32 related HWND hWnd; HINSTANCE hInst; LPWSTR appName; LPWSTR const className; int wndWidth; int wndHeight; //Direct3D 11 related ComPtr<ID3D11Device> pDevice; ComPtr<ID3D11DeviceContext> pContext; ComPtr<IDXGISwapChain> pSwapChain; ComPtr<ID3D11RenderTargetView> pRenderTargetView; ComPtr<ID3D11DepthStencilView> pDepthStencilView; ComPtr<ID3D11Texture2D> pDepthStencilBuffer; D3D11_VIEWPORT viewport; //Can be used to tweak d3d11 settings bool enable4xMSAA; bool enableFullscreen; //App states bool isAppPaused; bool isResizing; //Others Timer timer; FrameStats stats; bool isDestroyed; public: D3DApp(); ~D3DApp(); virtual bool init(); virtual bool onResize(); virtual void update(float dt) = 0; virtual void render() = 0; virtual void destroy(); virtual void run(); virtual LRESULT msgProc(HWND, UINT, WPARAM, LPARAM); virtual void onMouseDown(WPARAM btnState, int x, int y) {} virtual void onMouseUp(WPARAM btnState, int x, int y) {} virtual void onMouseMove(WPARAM btnState, int x, int y) {} virtual void onKeyDown(WPARAM keyState) {}; virtual void onKeyUp(WPARAM keyState) {}; private: //Implementation meant to be hidden //Not needed to be changed often bool _initWindow(); bool _initD3D(); }; extern D3DApp* gD3DApp; LRESULT CALLBACK gMsgProc(HWND, UINT, WPARAM, LPARAM);
  2. define to declare main() :-定义声明 main() :-
    In D3DApp.hD3DApp.h

     #ifndef IMPLEMENT_D3DAPP_MAIN #define IMPLEMENT_D3DAPP_MAIN(childClass) \\ INT CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, INT nShowCmd) \\ { \\ childClass app; \\ try { \\ if(!app.init()) \\ { \\ app.destroy(); \\ return 1; \\ } \\ app.run(); \\ } \\ catch(std::exception& e) \\ { \\ OutputDebugStringA(e.what()); \\ MessageBoxA(0, e.what(), "ERROR", MB_ICONERROR); \\ app.destroy(); \\ return 1; \\ } \\ app.destroy(); \\ return 0; \\ } #endif //IMPLEMENT_D3DAPP_MAIN
  3. And define for quick error checking :-并定义快速错误检查:-
    In D3DApp.hD3DApp.h

    #define HR(hr) \\ if(FAILED(hr)) { \\ std::ostringstream ss; \\ ss << "FILE: " << __FILE__ << std::endl << std::endl; \\ ss << "LINE: " << __LINE__ << std::endl << std::endl; \\ ss << "HRESULT = " << (hr) << std::endl; \\ throw std::exception(ss.str().c_str()); \\ }

It works like when a function call fails.它的工作原理类似于函数调用失败。 It is detected by HR() and it throws an std::exception, which is then caught in WinMain() try-catch block.它被 HR() 检测到并抛出一个 std::exception,然后被 WinMain() try-catch 块捕获。 Then the user can see the error in a MessageBox.然后用户可以在 MessageBox 中看到错误。

It should work nicely.它应该工作得很好。

But in my app :-但在我的应用程序中:-
In main.cppmain.cpp

#include "../Common/D3DApp.h"
#include "../Common/Helpers.h"
#include <sstream>
#include <DirectXMath.h>
#include <DirectXColors.h>


using namespace DirectX;


class Drawing : public D3DApp
{
public:
    ComPtr<ID3D11PixelShader> PS;
    ComPtr<ID3D11VertexShader> VS;

public:
    bool init() override
    {
        appName = L"Drawing in D3D11";
        if(!D3DApp::init())
            return false;

        //////////////////////////////////////////
        //////////////SHADERS////////////////////
        ComPtr<ID3DBlob> shaderBytecode;

        HR(CompileShader(L"simple.lsl", "VSMain", "vs_5_0", shaderBytecode.GetAddressOf()));
        HR(pDevice->CreateVertexShader(shaderBytecode->GetBufferPointer(), shaderBytecode->GetBufferSize(), nullptr, VS.GetAddressOf()));
        shaderBytecode.Reset();

        HR(CompileShader(L"simple.hlsl", "PSMain", "ps_5_0", shaderBytecode.GetAddressOf()));
        HR(pDevice->CreatePixelShader(shaderBytecode->GetBufferPointer(), shaderBytecode->GetBufferSize(), nullptr, PS.GetAddressOf()));
        shaderBytecode.Reset();
        //////////////SHADERS////////////////////

        //////////////SET STATES////////////////
        pContext->PSSetShader(PS.Get(), nullptr, 0);
        pContext->VSSetShader(VS.Get(), nullptr, 0);

        pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
        //////////////SET STATES////////////////

        /////////////////////////////////////////

        return true;
    }

    void update(float deltaTime) override
    {
    }

    void render() override
    {
        const float clearColour[4] = {0.f, 0.f, 1.f, 1.f};
        pContext->ClearRenderTargetView(pRenderTargetView.Get(), clearColour);
        pContext->ClearDepthStencilView(pDepthStencilView.Get(), D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.f, 1);

        pContext->Draw(3, 0);

        HR_PRESENT(pSwapChain->Present(0, 0));
    }

    void destroy() override
    {
        VS.Reset();
        PS.Reset();

        D3DApp::destroy();
    }
};

IMPLEMENT_D3DAPP_MAIN(Drawing);

To test the HR() define, I purposely invalidated a function argument from "simple.hlsl" to "simple.lsl" , as you can see when compiling the vertex shader.为了测试 HR() 定义,我故意使从"simple.hlsl""simple.lsl"的函数参数无效,正如您在编译顶点着色器时所看到的那样。

THE RESULT:结果:
1. The window is created. 1. 窗口已创建。 [OK] [好的]
2. A popup says, "Error in compiling shader: simple.lsl" [OK] 2.一个弹出窗口说,“编译着色器时出错:simple.lsl”[确定]
3. [Clicked ok] 3.【点击确定】
4. Again the same popup shows with same message [WTH?] 4. 同样的弹出窗口显示相同的消息 [WTH?]
5. [Clicked ok] 5.【点击确定】
6. Last popup of try-catch block, describing the file, line and HRESULT of the error [OK] 6、try-catch块的最后一个弹窗,描述错误的文件、行和HRESULT [OK]

Sorry, if my English is bland.对不起,如果我的英语平淡。
This may seem like a small problem.这似乎是一个小问题。 Yes, I can live with this.是的,我可以忍受这个。 But it is very very annoying.但它非常非常烦人。 Thanks for reading till here ;)感谢您阅读到这里;)
Thanks in advance.提前致谢。

Lets look at the HR macro:让我们看看HR宏:

#define HR(hr) \
if(FAILED(hr)) { \
    std::ostringstream ss; \
    ss << "FILE: " << __FILE__ << std::endl << std::endl; \
    ss << "LINE: " << __LINE__ << std::endl << std::endl; \
    ss << "HRESULT = " << (hr) << std::endl; \
    throw std::exception(ss.str().c_str()); \
}

You use the "argument" hr twice in the function, once in FAILED(hr) and once when you print the result.您在函数中使用“参数” hr两次,一次在FAILED(hr) ,一次在打印结果时。 That means hr will be evaluated twice.这意味着hr将被评估两次。 If you use a function call as the macro argument then the function will be called twice.如果您使用函数调用作为宏参数,则该函数将被调用两次。

The reason for this is because macros are not "called" at run-time, instead they replace the code before the C++ parser gets to the code.这样做的原因是因为宏不是在运行时“调用”的,而是在 C++ 解析器获取代码之前替换代码。

This is one major reason macros are often frowned upon, especially in C++.这是宏经常不受欢迎的主要原因之一,尤其是在 C++ 中。

Expand HR(CompileShader(L"simple.lsl", "VSMain", "vs_5_0", shaderBytecode.GetAddressOf()));展开HR(CompileShader(L"simple.lsl", "VSMain", "vs_5_0", shaderBytecode.GetAddressOf())); :

if(FAILED(CompileShader(L"simple.lsl", "VSMain", "vs_5_0", shaderBytecode.GetAddressOf())))) { \
    std::ostringstream ss; \
    ss << "FILE: " << __FILE__ << std::endl << std::endl; \
    ss << "LINE: " << __LINE__ << std::endl << std::endl; \
    ss << "HRESULT = " << (CompileShader(L"simple.lsl", "VSMain", "vs_5_0", shaderBytecode.GetAddressOf()))) << std::endl; \
    throw std::exception(ss.str().c_str()); \
};

You can see the problem now.你现在可以看到问题了。

Since you want __FILE__ and __LINE__ , you can use a function that takes the file and line as parameters由于您想要__FILE____LINE__ ,您可以使用一个将文件和行作为参数的函数

void HR_check(HRESULT hr, const char* file, int line)
{
    if (FAILED(hr)) {
        std::ostringstream ss;
        ss << "FILE: " << file << std::endl << std::endl;
        ss << "LINE: " << line << std::endl << std::endl;
        ss << "HRESULT = " << hr << std::endl;
        throw std::exception(ss.str().c_str());
    }
}

and combine it with a macro:并将其与宏结合起来:

#define HR(fn) HR_check(fn, __FILE__, __LINE__)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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