C++ 渲染目标->;GetSize不工作

C++ 渲染目标->;GetSize不工作,c++,gcc,windows-7-x64,direct2d,C++,Gcc,Windows 7 X64,Direct2d,为了学习Direct2D,我将从MSDN中学习 不过,我有一个问题。调用D2D1\u SIZE\u F rtSize=m\u pRenderTarget->GetSize()allways返回0,0的大小,并且在调试器中导致DrawLine调用出现异常。如果省略GetSize()调用,并用有效值填充D2D1_SIZE_F结构,它就会工作 初始化渲染目标的相关代码为: RECT rc; GetClientRect(m_hwnd, &rc); D2D1_SIZE_U

为了学习Direct2D,我将从MSDN中学习

不过,我有一个问题。调用
D2D1\u SIZE\u F rtSize=m\u pRenderTarget->GetSize()
allways返回0,0的大小,并且在调试器中导致
DrawLine
调用出现异常。如果省略GetSize()调用,并用有效值填充D2D1_SIZE_F结构,它就会工作

初始化渲染目标的相关代码为:

    RECT rc;
    GetClientRect(m_hwnd, &rc);

    D2D1_SIZE_U size = D2D1::SizeU(
        rc.right - rc.left,
        rc.bottom - rc.top
        );

    // Create a Direct2D render target.
    hr = m_pDirect2dFactory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(m_hwnd, size),
        &m_pRenderTarget
        );
我已经用调试器验证了有效值的大小是否超过了

图形代码中调用GetSize的部分:

    m_pRenderTarget->BeginDraw();

    m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());

    m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();
    // Draw a grid background.
    int width = static_cast<int>(rtSize.width);
    int height = static_cast<int>(rtSize.height);

    for (int x = 0; x < width; x += 10)
    {
        m_pRenderTarget->DrawLine(
            D2D1::Point2F(static_cast<FLOAT>(x), 0.0f),
            D2D1::Point2F(static_cast<FLOAT>(x), rtSize.height),
            m_pLightSlateGrayBrush,
            0.5f
            );
    }
m_pRenderTarget->BeginDraw();
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
D2D1_SIZE_F rtSize=m_pRenderTarget->GetSize();
//绘制网格背景。
int width=静态_cast(rtSize.width);
int height=静态施法(rtSize.height);
对于(int x=0;xDrawLine(
D2D1::点2F(静态投影(x),0.0f),
D2D1::Point2F(静态铸件(x)、rtSize.高度),
m_pLightSlateGrayBrush,
0.5f
);
}
所以我的问题是为什么GetSize()返回0,0并在以后导致AV

顺便说一句:我正在使用: Windows7终极64位 代码::块IDE TDM-GCC-64 GCC编译器v4.8.1 我在Unicode模式下编译
#定义Unicode
如果编译为32位或64位,则会出现问题(是的,我对64位模式进行了一些小调整,以确保在WndProc中有一个指向应用程序对象的有效指针)

为什么GetSize()返回0,0并在以后导致AV

因为GCC/MinGW-W64生成的对GetSize的调用与
d2d1.dll
中实现的调用约定不匹配。GetSize的返回类型
D2D\u SIZE\u F
是一个结构。根据,有两种方法可以从函数返回结构:

用户定义的类型可以通过全局函数和静态成员函数的值返回。要按RAX中的值返回用户定义的类型,其长度必须为1、2、4、8、16、32或64位。它还必须没有用户定义的构造函数、析构函数或复制赋值运算符。它不能有私有或受保护的非静态数据成员,也不能有引用类型的非静态数据成员。它不能有基类或虚函数。而且,它只能具有也满足这些要求的数据成员。(此定义基本上与C++03 POD类型相同。由于C++11标准中的定义已更改,我们不建议在此测试中使用std::is_POD。)否则,调用方必须为返回值分配内存,并将指向它的指针作为第一个参数传递

当GCC/MinGW-W64编译文章中的示例代码时,调用方仅为GetSize调用设置一个参数(在
rcx
),并希望在
rax
中返回值:

# AT&T syntax (destination operand last)
mov 0x10(%rbx),%rcx    # rcx <- pointer to IRenderContext
mov (%rcx),%rax        # rax <- pointer to virtual function table
callq *0x1a8(%rax)     # virtual function call (expect result in rax)
在GCC/MinGW-W64上,
rdx
中的值不是有效地址,因此当GetSize的实现尝试将返回值存储在内存中时,会发生访问冲突


D2D\u SIZE\u F
是一个64位POD结构(只是一个由两个浮点数组成的结构),因此在我看来,GCC在
rax
寄存器中返回它是正确的。我不知道是什么让Visual Studio使用指针返回,恐怕也不知道如何让GCC也这样做以实现兼容性。

我认为这实际上与调用约定的不明确或不正确的MS文档有关

根据该bug报告,如果返回结构无法放入寄存器,则其指针将位于RDX(第二个参数),而被调用的对象将位于RCX(第一个参数)。gcc以另一种方式执行,返回指针在RCX(第一个参数)中,调用对象在RDX(第二个参数)中

根据文档,哪种方法是正确的还不是100%清楚:文档中说要将返回值指针作为第一个参数。另外,表示
指针作为隐式第一个参数传递

显然,gcc和MSVC对这两条规则的适用顺序存在分歧。在我有限的测试中,似乎Clang同意MSVC,但我还不能完全遵循逻辑。Clang似乎确实将这种情况视为一种“thiscall”,而且是对的。我还没有弄清楚它实际上是如何将“this”指针放入RCX的,但这可能不是非常重要

回到这个问题,它不是按值返回结构。对于一个小的,MSVC在RAX中使用隐藏返回值而不是按值返回的唯一时间是当它是一个成员调用,并且是一个对象时。Clang同意,您可以在Clang IR中清楚地看到,它将对象指针放在第一位,隐藏的返回结构指针放在第二位:

call void @"?GetPixelSize@ID2D1RenderTarget@@QEBA?AUD2D_SIZE_U@@XZ"(%class.ID2D1RenderTarget* %4, %struct.D2D_SIZE_U* sret %2), !dbg !31
我怀疑这与gcc错误有关的原因是,我猜根本的问题是处理将“返回值指针”和“此指针”移动到参数列表中的顺序

gcc(我猜是吧?)首先处理被调用的对象,并将其作为新的第一个参数推送。然后它独立地查看返回对象,或者按值返回,或者将其作为新的第一个参数推送,最终将被调用的对象保留为第二个参数

Clang正在以另一种方式处理“循环”。它首先处理返回对象,但已经知道这是一个this调用,这就是它知道如何避免上面的ECX。如果它已经处理了被调用的对象指针,那么ECX就已经被分配了。然而,当决定返回是按值还是按隐藏对象指针时,它显然已经知道它正在处理一个this指针,因为这会产生差异

知道了这一点,从上面看到的
CCIfSRet
向后搜索,我发现了这个叮当声。这段代码没有命中,这就是为什么(如在编译器资源管理器中看到的)有一个ui
call void @"?GetPixelSize@ID2D1RenderTarget@@QEBA?AUD2D_SIZE_U@@XZ"(%class.ID2D1RenderTarget* %4, %struct.D2D_SIZE_U* sret %2), !dbg !31