SDL3窗口无法显示D3D11交换链渲染的粉色画面求助
我正在用SDL3和DX11开发自己的游戏引擎,已经尝试将HWND绑定到DX11交换链的OutputWindow,并且在SDL_AppIterate里写了清屏为粉色的逻辑,但运行后窗口始终是黑色,完全看不到预期的粉色画面。以下是我的完整代码:
#define SDL_MAIN_USE_CALLBACKS 1 #include "SDL3/SDL.h" #include "SDL3/SDL_main.h" #include "SDL3/SDL_events.h" #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "d3dcompiler.lib") #include <d3d11.h> #include <DirectXMath.h> #include <windows.h> SDL_Window* window; ID3D11Device* pD3D11Dev = NULL; ID3D11DeviceContext* pD3D11DevContext = NULL; IDXGISwapChain *pSwapChain = NULL; ID3D11Texture2D *pRenderTargetResource = NULL; ID3D11RenderTargetView *pBackBuffer = NULL; SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { if (!SDL_Init(SDL_INIT_VIDEO)) { return SDL_APP_FAILURE; } window = SDL_CreateWindow("Doctrina Editor", 640, 480, SDL_WINDOW_RESIZABLE); HWND hwnd = reinterpret_cast<HWND>(SDL_GetWindowFromID(SDL_GetWindowID(window))); int windowWidth, windowHeight; SDL_GetWindowSize(window, &windowWidth, &windowHeight); D3D_FEATURE_LEVEL featureLevelsRequested = D3D_FEATURE_LEVEL_11_0; D3D_FEATURE_LEVEL featureLevelsSupported; DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = 1; swapChainDesc.BufferDesc.Width = windowWidth; swapChainDesc.BufferDesc.Height = windowHeight; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferDesc.RefreshRate.Numerator = 60; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.Windowed = TRUE; HRESULT d3dHR = D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG, &featureLevelsRequested, 1, D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pD3D11Dev, &featureLevelsSupported, &pD3D11DevContext ); pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pRenderTargetResource); if (pRenderTargetResource != NULL) { pD3D11Dev->CreateRenderTargetView(pRenderTargetResource, NULL, &pBackBuffer); pRenderTargetResource->Release(); pD3D11DevContext->OMSetRenderTargets(1, &pBackBuffer, NULL); } D3D11_VIEWPORT viewPort = {}; viewPort.TopLeftX = 0; viewPort.TopLeftY = 0; viewPort.Width = windowWidth; viewPort.Height = windowHeight; pD3D11DevContext->RSSetViewports(1, &viewPort); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { if (event->type == SDL_EVENT_QUIT) { return SDL_APP_SUCCESS; } if (event->type == SDL_EVENT_WINDOW_RESIZED) { int newWidth = event->window.data1; int newHeight = event->window.data2; } return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void* appstate) { float color[4]; color[0] = 255.0f; color[1] = 0.0f; color[2] = 255.0f; color[3] = 1.0f; pD3D11DevContext->ClearRenderTargetView(pBackBuffer, color); pSwapChain->Present(1, 0); return SDL_APP_CONTINUE; } void SDL_AppQuit(void* appstate, SDL_AppResult result) { pSwapChain->Release(); pBackBuffer->Release(); pD3D11Dev->Release(); pD3D11DevContext->Release(); SDL_Quit(); }
问题分析与解决方案
我帮你找出了几个关键问题,逐个解决后应该就能看到粉色窗口了:
1. 最核心错误:SDL3窗口句柄(HWND)获取方式完全错误
你的代码里这行逻辑完全错误:
HWND hwnd = reinterpret_cast<HWND>(SDL_GetWindowFromID(SDL_GetWindowID(window)));
SDL_GetWindowFromID返回的是SDL_Window*类型的SDL窗口对象指针,根本不是Windows平台的HWND!强行把SDL对象指针转成HWND,会导致DX11交换链绑定到无效窗口,渲染内容完全不会输出到SDL窗口上,所以窗口显示SDL默认的黑色背景。
正确的HWND获取方式(SDL3):
SDL3提供了SDL_GetWindowNativeHandle函数获取平台原生窗口句柄,Windows系统下返回值就是HWND:
HWND hwnd = reinterpret_cast<HWND>(SDL_GetWindowNativeHandle(window));
2. 颜色值范围不符合DX11要求
DX11的ClearRenderTargetView要求颜色分量是0.0f~1.0f之间的浮点数,你当前写的255.0f虽然会被DX11自动 clamp 到1.0f,但属于不规范写法,且可能在部分驱动下出现异常。正确的粉色应该是:
float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
3. 缺失DX11 API的错误检查
代码中D3D11CreateDeviceAndSwapChain、GetBuffer、CreateRenderTargetView等DX11调用都没有检查返回值,如果这些步骤失败,后续指针会是NULL,导致渲染逻辑完全不执行。必须添加错误检查,比如:
HRESULT d3dHR = D3D11CreateDeviceAndSwapChain(...); if (FAILED(d3dHR)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建D3D11设备失败: 0x%X", d3dHR); return SDL_APP_FAILURE; }
4. 窗口Resize时未更新交换链与渲染目标
当前代码处理了窗口Resize事件,但没有重建交换链、更新渲染目标和视口,窗口调整大小后会显示异常。虽然这不是初始窗口黑色的原因,但也是必须修复的后续问题。
修正后的核心代码片段
以下是修正后的SDL_AppInit和SDL_AppIterate关键部分:
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { if (!SDL_Init(SDL_INIT_VIDEO)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL初始化失败"); return SDL_APP_FAILURE; } window = SDL_CreateWindow("Doctrina Editor", 640, 480, SDL_WINDOW_RESIZABLE); if (!window) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建SDL窗口失败"); SDL_Quit(); return SDL_APP_FAILURE; } // 正确获取HWND HWND hwnd = reinterpret_cast<HWND>(SDL_GetWindowNativeHandle(window)); if (!hwnd) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "获取窗口HWND失败"); SDL_DestroyWindow(window); SDL_Quit(); return SDL_APP_FAILURE; } int windowWidth, windowHeight; SDL_GetWindowSize(window, &windowWidth, &windowHeight); D3D_FEATURE_LEVEL featureLevelsRequested = D3D_FEATURE_LEVEL_11_0; D3D_FEATURE_LEVEL featureLevelsSupported; DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = 1; swapChainDesc.BufferDesc.Width = windowWidth; swapChainDesc.BufferDesc.Height = windowHeight; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferDesc.RefreshRate.Numerator = 60; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = hwnd; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.Windowed = TRUE; HRESULT d3dHR = D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG, &featureLevelsRequested, 1, D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pD3D11Dev, &featureLevelsSupported, &pD3D11DevContext ); if (FAILED(d3dHR)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建D3D11设备失败: 0x%X", d3dHR); SDL_DestroyWindow(window); SDL_Quit(); return SDL_APP_FAILURE; } d3dHR = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pRenderTargetResource)); if (FAILED(d3dHR) || !pRenderTargetResource) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "获取交换链缓冲区失败: 0x%X", d3dHR); return SDL_APP_FAILURE; } d3dHR = pD3D11Dev->CreateRenderTargetView(pRenderTargetResource, NULL, &pBackBuffer); pRenderTargetResource->Release(); if (FAILED(d3dHR) || !pBackBuffer) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建渲染目标视图失败: 0x%X", d3dHR); return SDL_APP_FAILURE; } pD3D11DevContext->OMSetRenderTargets(1, &pBackBuffer, NULL); D3D11_VIEWPORT viewPort = {}; viewPort.TopLeftX = 0; viewPort.TopLeftY = 0; viewPort.Width = static_cast<float>(windowWidth); viewPort.Height = static_cast<float>(windowHeight); viewPort.MinDepth = 0.0f; viewPort.MaxDepth = 1.0f; pD3D11DevContext->RSSetViewports(1, &viewPort); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void* appstate) { const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; pD3D11DevContext->ClearRenderTargetView(pBackBuffer, color); pSwapChain->Present(1, 0); return SDL_APP_CONTINUE; }
最后验证
按照上述修改后重新编译运行,应该就能看到粉色的SDL窗口了。如果仍有问题,可以查看DX11调试层的输出日志(你已开启D3D11_CREATE_DEVICE_DEBUG),里面会详细提示错误原因。
内容来源于stack exchange

