如何从VRAM释放SDL_Texture?

时间:2018-12-10 10:53:26

标签: sdl sdl-2

我对SDL_Texture的理解是:

  1. 调用SDL_CreateTextureFromSurface()时,SDL_Texture位于主内存上。
  2. 调用SDL_RenderCopy()时,纹理位于VRAM上。
  3. 调用SDL_DestroyTexture()时,纹理将从VRAM和主内存中释放。

我正确吗?

我正在制作一个应用程序,可以在渲染图像之前一次从图像文件一次创建很多纹理,因为图像非常大,并且SDL_CreateTextureFromSurface()需要很长时间。当我依次使用SDL_RenderCopy()和SDL_RenderPresent()渲染它们时,VRAM的使用量逐渐增加,并且在达到最大使用量后应用程序变慢。

我想从VRAM中释放纹理,但又不想从主内存中释放纹理,因为重新创建纹理需要很长时间。有可能吗?

这是最小代码。它可以工作到专用GPU内存使用率达到100%为止。在那之后,它变得非常缓慢。 (Windows10,Visual Studio 2017,NVIDIA P6000)

#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include <thread>
#include <chrono>

#include "SDL.h"
#include "SDL_image.h"

int main(int argc, char** argv) {


    std::vector<SDL_Texture*> texture_list;
    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window* window = SDL_CreateWindow( "", 0, 0, 7680, 4320, SDL_WINDOW_BORDERLESS);

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    namespace fs = std::experimental::filesystem;

    for ( auto ent : fs::recursive_directory_iterator("c:\\picture\\1k") ) {
        if(!fs::is_directory(ent)){
            auto f = ent.path().generic_string();
            auto surface = IMG_Load(f.c_str());
            std::cout << "file:" << f << std::endl;
            auto tex = SDL_CreateTextureFromSurface(renderer, surface);
            if(!tex){
                std::cout << "SDL_CreateTextureFromSurface error" << std::endl;
                std::cout << SDL_GetError() << std::endl;
            }
            texture_list.push_back(tex);

            SDL_FreeSurface(surface);
        }
    }

    while (true) {
        for (auto tex : texture_list) {

            if(SDL_RenderClear(renderer) != 0){
                std::cout << "SDL_RenderClear error" << std::endl;
                std::cout << SDL_GetError() << std::endl;
            }
            if(SDL_RenderCopy(renderer, tex, NULL, NULL) < 0){
                std::cout << "SDL_RenderCopy error" << std::endl;
                std::cout << SDL_GetError() << std::endl;
            }
            SDL_RenderPresent(renderer);

            SDL_Delay(1);
            //std::cout << cnt++ << std::endl;
            SDL_Event event;

            if(SDL_PollEvent(&event)){
                std::cout << event.type << std::endl;
                switch (event.type) {
                    case SDL_KEYDOWN:
                        switch (event.key.keysym.sym) {
                            case SDLK_q:
                                exit(0);

                        }
                        break;
                }
            }
        }
    }

    return 0;
}

1 个答案:

答案 0 :(得分:0)

每个纹理一次都可以发生!

(也许您打算这样做,但似乎没有用;幻灯片的设计更短,更好)

在主循环开始时,每次主循环迭代应该只调用一次SDL_RenderClear。同样,您应该只在主循环的末尾与SDL_RenderPresent一起呼叫SDL_PollEvent

while (true) {
    if(SDL_RenderClear(renderer) != 0){
        std::cout << "SDL_RenderClear error" << std::endl;
        std::cout << SDL_GetError() << std::endl;
    }

    for (auto tex : texture_list) {
        if(SDL_RenderCopy(renderer, tex, NULL, NULL) < 0){
            std::cout << "SDL_RenderCopy error" << std::endl;
            std::cout << SDL_GetError() << std::endl;
        }
    }

    SDL_RenderPresent(renderer);

    SDL_Delay(1);
    //std::cout << cnt++ << std::endl;
    SDL_Event event;

    if(SDL_PollEvent(&event)){
        std::cout << event.type << std::endl;
        switch (event.type) {
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym) {
                    case SDLK_q:
                        exit(0);

                }
                break;
        }
    }
}

请注意,SDL_RenderCopy缺少目标矩形,因此每个纹理都将在前一个纹理上绘制...

如果您要做想要幻灯片放映。您最好先 not 先创建所有纹理,然后尝试在幻灯片切换时按需构建它们,或者创建流纹理并更新像素(可能如果您使用不同尺寸的图像,效果不佳