2023-07-26 20:09:57 +02:00
|
|
|
#include "./sdlrenderer_texture_uploader.hpp"
|
|
|
|
|
|
|
|
#include <cassert>
|
2024-03-08 22:04:58 +01:00
|
|
|
#include <cstdint>
|
|
|
|
#include <cstring>
|
2024-10-05 13:53:55 +02:00
|
|
|
#include <memory>
|
2023-07-26 20:09:57 +02:00
|
|
|
|
2024-03-09 16:26:35 +01:00
|
|
|
#include <iostream>
|
|
|
|
|
2024-10-05 13:53:55 +02:00
|
|
|
static SDL_PixelFormat format2sdl(TextureUploaderI::Format format) {
|
|
|
|
switch (format) {
|
|
|
|
case TextureUploaderI::Format::RGBA: return SDL_PIXELFORMAT_RGBA32;
|
|
|
|
//case TextureUploaderI::Format::RGB: return SDL_PIXELFORMAT_RGB24;
|
|
|
|
case TextureUploaderI::Format::IYUV: return SDL_PIXELFORMAT_IYUV;
|
|
|
|
case TextureUploaderI::Format::YV12: return SDL_PIXELFORMAT_YV12;
|
|
|
|
case TextureUploaderI::Format::NV12: return SDL_PIXELFORMAT_NV12;
|
|
|
|
case TextureUploaderI::Format::NV21: return SDL_PIXELFORMAT_NV21;
|
|
|
|
case TextureUploaderI::Format::MAX: return SDL_PIXELFORMAT_UNKNOWN;
|
|
|
|
}
|
|
|
|
return SDL_PIXELFORMAT_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2023-07-26 20:09:57 +02:00
|
|
|
SDLRendererTextureUploader::SDLRendererTextureUploader(SDL_Renderer* renderer_) :
|
|
|
|
renderer(renderer_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-03-08 22:04:58 +01:00
|
|
|
uint64_t SDLRendererTextureUploader::uploadRGBA(const uint8_t* data, uint32_t width, uint32_t height, Filter filter, Access access) {
|
2024-10-05 13:53:55 +02:00
|
|
|
return upload(data, width, height, Format::RGBA, filter, access);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SDLRendererTextureUploader::updateRGBA(uint64_t tex_id, const uint8_t* data, size_t size) {
|
|
|
|
return update(tex_id, data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t SDLRendererTextureUploader::upload(const uint8_t* data, uint32_t width, uint32_t height, Format format, Filter filter, Access access) {
|
|
|
|
const auto sdl_format = format2sdl(format);
|
|
|
|
if (sdl_format == SDL_PIXELFORMAT_UNKNOWN) {
|
|
|
|
std::cerr << "SDLRTU error: unsupported format '" << format << "'\n";
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: why do we even create a non owning surface here???
|
|
|
|
std::unique_ptr<SDL_Surface, decltype(&SDL_DestroySurface)> surf = {
|
|
|
|
SDL_CreateSurfaceFrom(
|
|
|
|
width, height,
|
|
|
|
sdl_format,
|
|
|
|
(void*)data,
|
|
|
|
4*width // ???
|
|
|
|
),
|
|
|
|
&SDL_DestroySurface
|
|
|
|
};
|
|
|
|
|
|
|
|
assert(surf);
|
|
|
|
if (!surf) {
|
|
|
|
std::cerr << "SDLRTU error: surf creation failed " << SDL_GetError() << "\n";
|
|
|
|
return 0;
|
|
|
|
}
|
2023-07-26 20:09:57 +02:00
|
|
|
|
2024-03-09 16:26:35 +01:00
|
|
|
SDL_Texture* tex = SDL_CreateTexture(
|
|
|
|
renderer,
|
2024-07-18 12:22:15 +02:00
|
|
|
surf->format,
|
2024-03-09 16:26:35 +01:00
|
|
|
access == Access::STREAMING ? SDL_TEXTUREACCESS_STREAMING : SDL_TEXTUREACCESS_STATIC,
|
|
|
|
surf->w, surf->h
|
|
|
|
);
|
2024-10-05 13:53:55 +02:00
|
|
|
|
|
|
|
assert(tex);
|
|
|
|
if (tex == nullptr) {
|
|
|
|
std::cerr << "SDLRTU error: tex creation failed " << SDL_GetError() << "\n";
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool need_to_lock = SDL_MUSTLOCK(surf);
|
|
|
|
if (need_to_lock) {
|
|
|
|
if (!SDL_LockSurface(surf.get())) {
|
|
|
|
std::cerr << "SDLRTU error: failed to lock surface " << SDL_GetError() << "\n";
|
|
|
|
SDL_DestroyTexture(tex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SDL_UpdateTexture(tex, nullptr, surf->pixels, surf->pitch)) {
|
|
|
|
std::cerr << "SDLRTU error: tex update failed " << SDL_GetError() << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (need_to_lock) {
|
|
|
|
// error check?
|
|
|
|
SDL_UnlockSurface(surf.get());
|
|
|
|
}
|
2024-01-21 20:20:32 +01:00
|
|
|
|
2024-06-01 12:51:50 +02:00
|
|
|
SDL_BlendMode surf_blend_mode = SDL_BLENDMODE_NONE;
|
2024-10-05 13:53:55 +02:00
|
|
|
if (SDL_GetSurfaceBlendMode(surf.get(), &surf_blend_mode)) {
|
2024-06-01 12:51:50 +02:00
|
|
|
SDL_SetTextureBlendMode(tex, surf_blend_mode);
|
|
|
|
}
|
|
|
|
|
2024-01-21 13:58:22 +01:00
|
|
|
if (filter == NEAREST) {
|
2024-01-21 20:20:32 +01:00
|
|
|
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_NEAREST);
|
2024-01-21 13:58:22 +01:00
|
|
|
} else if (filter == LINEAR) {
|
2024-01-21 20:20:32 +01:00
|
|
|
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_LINEAR);
|
2024-01-21 13:58:22 +01:00
|
|
|
}
|
|
|
|
|
2023-07-26 20:09:57 +02:00
|
|
|
return reinterpret_cast<uint64_t>(tex);
|
|
|
|
}
|
|
|
|
|
2024-10-05 13:53:55 +02:00
|
|
|
bool SDLRendererTextureUploader::update(uint64_t tex_id, const uint8_t* data, size_t size) {
|
2024-03-08 22:04:58 +01:00
|
|
|
auto* texture = static_cast<SDL_Texture*>(reinterpret_cast<void*>(tex_id));
|
|
|
|
if (texture == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t* pixels = nullptr;
|
|
|
|
int pitch = 0;
|
|
|
|
|
2024-09-19 14:01:47 +02:00
|
|
|
if (!SDL_LockTexture(texture, nullptr, (void**)&pixels, &pitch)) {
|
2024-03-09 16:26:35 +01:00
|
|
|
std::cerr << "SDLRTU error: failed locking texture '" << SDL_GetError() << "'\n";
|
2024-03-08 22:04:58 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::memcpy(pixels, data, size);
|
|
|
|
|
|
|
|
SDL_UnlockTexture(texture);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-07-26 20:09:57 +02:00
|
|
|
void SDLRendererTextureUploader::destroy(uint64_t tex_id) {
|
|
|
|
SDL_DestroyTexture(static_cast<SDL_Texture*>(reinterpret_cast<void*>(tex_id)));
|
|
|
|
}
|
|
|
|
|