SDL_Texture 调整大小后呈现黑色,除非重新绘制
SDL_Texture renders black after resize unless it is redrawn
我有一个讨厌的错误要告诉你们。 (是的,这可能是我的错误,而不是 SDL 的。)我一直在为 SDL 编写现代 C++ 包装器,一切似乎都按预期工作。然而,我的纹理 class 有一个奇怪的错误:如果它在调整大小后重绘,它看起来很好,但如果不是,它就会变成全黑。这是它的样子:
Before the resize
After the resize
我不能完全 post 这里只是代码的一部分,所以这里是整个文件夹(托管在 GitLab 上):SDL wrapper
这是一个使用这个库重现错误的小程序:
#include "sdl_wrapper/context.hh"
#include "sdl_wrapper/video/context.hh"
#include "sdl_wrapper/render/renderer.hh"
#include "sdl_wrapper/render/texture.hh"
#include "sdl_wrapper/colors.hh"
#include "SDL2/SDL_events.h"
int main()
{
sdl::Context sdlContext;
sdl::video::Context videoContext = sdlContext.initVideo();
sdl::video::Window window = videoContext.createWindow("test", 0, 0, 800, 600).resizable().build();
int width = 800;
int height = 600;
sdl::render::Renderer renderer = window.createRenderer().targetTexture().build();
sdl::render::Texture example(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 400, 300);
renderer.setTarget(example);
renderer.setDrawColor(sdl::colors::Blue);
renderer.clear();
renderer.resetTarget();
bool run = true;
while (run)
{
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
run = false;
break;
}
}
renderer.setDrawColor({0x44, 0x44, 0x44, 0xff});
renderer.clear();
renderer.copy(example, std::nullopt, {{width / 4, height / 4, example.getWidth(), example.getHeight()}});
renderer.present();
}
}
要重现,只需 运行 这个程序并调整 window 的大小。调整大小后会有一个蓝色方块变成黑色。
如果有人能在这里指出正确的方向,我将不胜感激。我真的很想避免在每次调整大小时都重新绘制(如果我被误导了,请在这一点上与我争论)。
SDL 不承诺保留目标纹理数据。在某些情况下,尤其是对于 d3d 或移动设备,数据会由于一些大的状态更改而丢失。更改 window 大小听起来可能不大,但在某些 hardware/driver 配置上会导致问题,我想这就是 SDL 检测调整大小并丢弃所有渲染器数据的原因。当您需要更新渲染纹理时,您会收到 SDL_RENDER_TARGETS_RESET
事件。
这不应该发生在例如opengl 渲染器实现(听起来不错,但背后的原因并不是那么好);在 windows 上,SDL2 默认为 direct3d,可以通过发出 SDL_SetHint
或设置 envvars.
进行修改
我有一个讨厌的错误要告诉你们。 (是的,这可能是我的错误,而不是 SDL 的。)我一直在为 SDL 编写现代 C++ 包装器,一切似乎都按预期工作。然而,我的纹理 class 有一个奇怪的错误:如果它在调整大小后重绘,它看起来很好,但如果不是,它就会变成全黑。这是它的样子:
Before the resize
After the resize
我不能完全 post 这里只是代码的一部分,所以这里是整个文件夹(托管在 GitLab 上):SDL wrapper
这是一个使用这个库重现错误的小程序:
#include "sdl_wrapper/context.hh" #include "sdl_wrapper/video/context.hh" #include "sdl_wrapper/render/renderer.hh" #include "sdl_wrapper/render/texture.hh" #include "sdl_wrapper/colors.hh" #include "SDL2/SDL_events.h" int main() { sdl::Context sdlContext; sdl::video::Context videoContext = sdlContext.initVideo(); sdl::video::Window window = videoContext.createWindow("test", 0, 0, 800, 600).resizable().build(); int width = 800; int height = 600; sdl::render::Renderer renderer = window.createRenderer().targetTexture().build(); sdl::render::Texture example(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 400, 300); renderer.setTarget(example); renderer.setDrawColor(sdl::colors::Blue); renderer.clear(); renderer.resetTarget(); bool run = true; while (run) { SDL_Event e; while (SDL_PollEvent(&e) != 0) { if (e.type == SDL_QUIT) { run = false; break; } } renderer.setDrawColor({0x44, 0x44, 0x44, 0xff}); renderer.clear(); renderer.copy(example, std::nullopt, {{width / 4, height / 4, example.getWidth(), example.getHeight()}}); renderer.present(); } }
要重现,只需 运行 这个程序并调整 window 的大小。调整大小后会有一个蓝色方块变成黑色。
如果有人能在这里指出正确的方向,我将不胜感激。我真的很想避免在每次调整大小时都重新绘制(如果我被误导了,请在这一点上与我争论)。
SDL 不承诺保留目标纹理数据。在某些情况下,尤其是对于 d3d 或移动设备,数据会由于一些大的状态更改而丢失。更改 window 大小听起来可能不大,但在某些 hardware/driver 配置上会导致问题,我想这就是 SDL 检测调整大小并丢弃所有渲染器数据的原因。当您需要更新渲染纹理时,您会收到 SDL_RENDER_TARGETS_RESET
事件。
这不应该发生在例如opengl 渲染器实现(听起来不错,但背后的原因并不是那么好);在 windows 上,SDL2 默认为 direct3d,可以通过发出 SDL_SetHint
或设置 envvars.