Как освободить SDL_Texture от VRAM? - PullRequest
0 голосов
/ 10 декабря 2018

Я понимаю, что такое 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 голосов
/ 12 декабря 2018

У вас все происходит один раз для текстуры!

(Может быть, вы это и предполагали, но это не кажется полезным; есть более короткие и лучшие дизайны для слайд-шоу)

вы должны звонить 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 отсутствует прямоугольник назначения, поэтому каждая текстура будет нарисована поверхпредыдущий ...

Если вы делаете хотите слайд-шоу.Возможно, вам лучше было бы , а не создавать все текстуры заранее и вместо этого попытаться создавать их по требованию при переключении слайдов или создании одиночной потоковой текстуры и обновлении пикселей (может не работатьхорошо, если ваши изображения разных размеров)

...