mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-30 01:37:28 +01:00
feat(vulkan): vulkan 1.4 core with the user interface and the launcher, shaders split into ogl46/vk14 with SPIR-V binaries loaded first
This commit is contained in:
@@ -43,7 +43,7 @@ struct texture_request {
|
||||
int height { 0 };
|
||||
int mapcount { 0 };
|
||||
int blocksize { 0 };
|
||||
// handed to the workers (opengl_texture::prefetch()), and when: the main thread only
|
||||
// handed to the workers (texture_source::prefetch()), and when: the main thread only
|
||||
bool submitted { false };
|
||||
std::chrono::steady_clock::time_point submittime;
|
||||
bool ahead { false }; // read ahead of the camera, which was at the origin then
|
||||
@@ -138,7 +138,7 @@ private:
|
||||
m_read.notify_all();
|
||||
} }
|
||||
|
||||
// same as the reading part of opengl_texture::load_DDS()
|
||||
// same as the reading part of texture_source::load_DDS()
|
||||
static void read( texture_request &Request ) {
|
||||
std::ifstream file( Request.file, std::ios::binary );
|
||||
if( false == file.is_open() ) {
|
||||
@@ -182,7 +182,7 @@ private:
|
||||
std::array<GLuint, gl::MAX_TEXTURES + gl::HELPER_TEXTURES> opengl_texture::units = { 0 };
|
||||
GLint opengl_texture::m_activeunit = -1;
|
||||
|
||||
std::unordered_map<GLint, int> opengl_texture::precompressed_formats =
|
||||
std::unordered_map<GLint, int> texture_source::precompressed_formats =
|
||||
{
|
||||
{ GL_COMPRESSED_RGBA8_ETC2_EAC, 16 },
|
||||
{ GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, 16 },
|
||||
@@ -257,16 +257,25 @@ std::unordered_map<GLint, std::unordered_map<GLint, GLint>> opengl_texture::mapp
|
||||
{ GL_RED, GL_R8 } } },
|
||||
};
|
||||
|
||||
texture_manager::texture_manager() {
|
||||
texture_bank::texture_bank( std::function<texture_source *()> Make ) :
|
||||
m_make( std::move( Make ) ) {
|
||||
|
||||
// since index 0 is used to indicate no texture, we put a blank entry in the first texture slot
|
||||
m_textures.emplace_back( new opengl_texture(), std::chrono::steady_clock::time_point() );
|
||||
m_textures.emplace_back( m_make(), std::chrono::steady_clock::time_point() );
|
||||
}
|
||||
|
||||
texture_bank::~texture_bank() {
|
||||
|
||||
delete_textures();
|
||||
}
|
||||
|
||||
texture_manager::texture_manager() :
|
||||
texture_bank( []() -> texture_source * { return new opengl_texture(); } ) {}
|
||||
|
||||
// loads texture data from specified file
|
||||
// TODO: wrap it in a workitem class, for the job system deferred loading
|
||||
void
|
||||
opengl_texture::load() {
|
||||
texture_source::load() {
|
||||
if (data_state == resource_state::good)
|
||||
return;
|
||||
|
||||
@@ -319,11 +328,11 @@ fail:
|
||||
data_state = resource_state::failed;
|
||||
ErrorLog( "Bad texture: failed to load texture \"" + name + "\"" );
|
||||
// NOTE: temporary workaround for texture assignment errors
|
||||
id = 0;
|
||||
on_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
void opengl_texture::load_PNG()
|
||||
void texture_source::load_PNG()
|
||||
{
|
||||
//png_image png;
|
||||
//memset(&png, 0, sizeof(png_image));
|
||||
@@ -370,7 +379,7 @@ void opengl_texture::load_PNG()
|
||||
//data_state = resource_state::good;
|
||||
}
|
||||
|
||||
void opengl_texture::load_STBI()
|
||||
void texture_source::load_STBI()
|
||||
{
|
||||
int x, y, n;
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
@@ -395,7 +404,7 @@ void opengl_texture::load_STBI()
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::make_stub()
|
||||
texture_source::make_stub()
|
||||
{
|
||||
data_width = 2;
|
||||
data_height = 2;
|
||||
@@ -410,7 +419,7 @@ opengl_texture::make_stub()
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::make_from_memory(size_t width, size_t height, const uint8_t *raw)
|
||||
texture_source::make_from_memory(size_t width, size_t height, const uint8_t *raw)
|
||||
{
|
||||
release();
|
||||
|
||||
@@ -467,7 +476,7 @@ void opengl_texture::update_from_memory(size_t width, size_t height, const uint8
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::make_request() {
|
||||
texture_source::make_request() {
|
||||
|
||||
auto const components { Split( name, '?' ) };
|
||||
|
||||
@@ -479,7 +488,7 @@ opengl_texture::make_request() {
|
||||
Application.request( { ToLower( components.front() ), dictionary, rt } );
|
||||
}
|
||||
|
||||
DDCOLORKEY opengl_texture::deserialize_ddck(std::istream &s)
|
||||
DDCOLORKEY texture_source::deserialize_ddck(std::istream &s)
|
||||
{
|
||||
DDCOLORKEY ddck;
|
||||
|
||||
@@ -489,7 +498,7 @@ DDCOLORKEY opengl_texture::deserialize_ddck(std::istream &s)
|
||||
return ddck;
|
||||
}
|
||||
|
||||
DDPIXELFORMAT opengl_texture::deserialize_ddpf(std::istream &s)
|
||||
DDPIXELFORMAT texture_source::deserialize_ddpf(std::istream &s)
|
||||
{
|
||||
DDPIXELFORMAT ddpf;
|
||||
|
||||
@@ -505,7 +514,7 @@ DDPIXELFORMAT opengl_texture::deserialize_ddpf(std::istream &s)
|
||||
return ddpf;
|
||||
}
|
||||
|
||||
DDSCAPS2 opengl_texture::deserialize_ddscaps(std::istream &s)
|
||||
DDSCAPS2 texture_source::deserialize_ddscaps(std::istream &s)
|
||||
{
|
||||
DDSCAPS2 ddsc;
|
||||
|
||||
@@ -517,7 +526,7 @@ DDSCAPS2 opengl_texture::deserialize_ddscaps(std::istream &s)
|
||||
return ddsc;
|
||||
}
|
||||
|
||||
DDSURFACEDESC2 opengl_texture::deserialize_ddsd(std::istream &s)
|
||||
DDSURFACEDESC2 texture_source::deserialize_ddsd(std::istream &s)
|
||||
{
|
||||
DDSURFACEDESC2 ddsd;
|
||||
|
||||
@@ -544,7 +553,7 @@ DDSURFACEDESC2 opengl_texture::deserialize_ddsd(std::istream &s)
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::load_DDS() {
|
||||
texture_source::load_DDS() {
|
||||
|
||||
std::ifstream file( name + type, std::ios::binary | std::ios::ate ); file.unsetf( std::ios::skipws );
|
||||
std::size_t filesize = static_cast<size_t>(file.tellg()); // ios::ate already positioned us at the end of the file
|
||||
@@ -689,7 +698,7 @@ opengl_texture::load_DDS() {
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::load_KTX() {
|
||||
texture_source::load_KTX() {
|
||||
std::ifstream file( name + type, std::ios::binary | std::ios::ate ); file.unsetf( std::ios::skipws );
|
||||
std::size_t filesize = static_cast<size_t>(file.tellg()); // ios::ate already positioned us at the end of the file
|
||||
file.seekg( 0, std::ios::beg ); // rewind the caret afterwards
|
||||
@@ -749,7 +758,7 @@ opengl_texture::load_KTX() {
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::load_TEX() {
|
||||
texture_source::load_TEX() {
|
||||
|
||||
std::ifstream file( name + type, std::ios::binary ); file.unsetf( std::ios::skipws );
|
||||
|
||||
@@ -796,7 +805,7 @@ opengl_texture::load_TEX() {
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::load_TGA() {
|
||||
texture_source::load_TGA() {
|
||||
|
||||
std::ifstream file( name + type, std::ios::binary ); file.unsetf( std::ios::skipws );
|
||||
|
||||
@@ -1121,7 +1130,7 @@ opengl_texture::create( bool const Static ) {
|
||||
|
||||
// takes over the data read by a worker thread, waiting for it if needed
|
||||
void
|
||||
opengl_texture::complete_data() {
|
||||
texture_source::complete_data() {
|
||||
|
||||
if( request == nullptr ) { return; }
|
||||
|
||||
@@ -1134,7 +1143,7 @@ opengl_texture::complete_data() {
|
||||
data_state = resource_state::failed;
|
||||
ErrorLog( "Bad texture: failed to load texture \"" + name + "\"" );
|
||||
// NOTE: temporary workaround for texture assignment errors, same as in load()
|
||||
id = 0;
|
||||
on_failed();
|
||||
return;
|
||||
}
|
||||
data.swap( completed->data );
|
||||
@@ -1144,10 +1153,10 @@ opengl_texture::complete_data() {
|
||||
|
||||
// has a worker thread read the data of the texture, if it's waiting for that. Origin: the camera, for data read ahead of it
|
||||
void
|
||||
opengl_texture::prefetch( glm::dvec3 const *Origin ) {
|
||||
texture_source::prefetch( glm::dvec3 const *Origin ) {
|
||||
|
||||
if( ( request == nullptr )
|
||||
&& ( id == invalid_id )
|
||||
&& ( false == resident() )
|
||||
&& ( data_state == resource_state::none )
|
||||
&& ( true == reload_on_use )
|
||||
&& ( true == streamed() ) ) {
|
||||
@@ -1169,7 +1178,7 @@ opengl_texture::prefetch( glm::dvec3 const *Origin ) {
|
||||
// the data of the texture is read from its file by worker threads when it's needed (gfx.textures.streaming), and not kept
|
||||
// after the upload: it can be read again
|
||||
bool
|
||||
opengl_texture::streamed() const {
|
||||
texture_source::streamed() const {
|
||||
|
||||
return ( ( true == Global.gfx_texture_streaming )
|
||||
&& ( type == ".dds" )
|
||||
@@ -1256,7 +1265,7 @@ opengl_texture::alloc_rendertarget( GLint format, GLint components, int width, i
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::set_components_hint( GLint hint ) {
|
||||
texture_source::set_components_hint( GLint hint ) {
|
||||
|
||||
components_hint = hint;
|
||||
}
|
||||
@@ -1284,7 +1293,7 @@ opengl_texture::set_filtering() const
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::downsize( GLuint const Format ) {
|
||||
texture_source::downsize( GLuint const Format ) {
|
||||
|
||||
while( data_width > Global.CurrentMaxTextureSize || data_height > Global.CurrentMaxTextureSize ) {
|
||||
// scale down the base texture, if it's larger than allowed maximum
|
||||
@@ -1313,7 +1322,7 @@ opengl_texture::downsize( GLuint const Format ) {
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::flip_vertical() {
|
||||
texture_source::flip_vertical() {
|
||||
|
||||
auto const swapsize { data_width * 4 };
|
||||
auto destination { data.begin() + ( data_height - 1 ) * swapsize };
|
||||
@@ -1338,7 +1347,7 @@ texture_manager::unit( GLint const Textureunit ) {
|
||||
|
||||
// ustalenie numeru tekstury, wczytanie jeśli jeszcze takiej nie było
|
||||
texture_handle
|
||||
texture_manager::create( std::string Filename, bool const Loadnow, GLint Formathint ) {
|
||||
texture_bank::create( std::string Filename, bool const Loadnow, GLint Formathint ) {
|
||||
|
||||
if( contains( Filename, '|' ) ) {
|
||||
Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
|
||||
@@ -1411,7 +1420,7 @@ texture_manager::create( std::string Filename, bool const Loadnow, GLint Formath
|
||||
}
|
||||
}
|
||||
|
||||
auto texture = new opengl_texture();
|
||||
auto texture = m_make();
|
||||
texture->name = locator.first;
|
||||
texture->type = locator.second;
|
||||
texture->traits = traits;
|
||||
@@ -1424,9 +1433,9 @@ texture_manager::create( std::string Filename, bool const Loadnow, GLint Formath
|
||||
|
||||
if( true == Loadnow ) {
|
||||
|
||||
texture_manager::texture( textureindex ).load();
|
||||
texture_bank::texture( textureindex ).load();
|
||||
#ifndef EU07_DEFERRED_TEXTURE_UPLOAD
|
||||
texture_manager::texture( textureindex ).create();
|
||||
texture_bank::texture( textureindex ).create();
|
||||
// texture creation binds a different texture, force a re-bind on next use
|
||||
m_activetexture = -1;
|
||||
#endif
|
||||
@@ -1446,8 +1455,8 @@ texture_manager::bind( std::size_t const Unit, texture_handle const Texture ) {
|
||||
opengl_texture::unbind(Unit);
|
||||
}
|
||||
|
||||
opengl_texture &
|
||||
texture_manager::mark_as_used(const texture_handle Texture) {
|
||||
texture_source &
|
||||
texture_bank::mark_as_used(const texture_handle Texture) {
|
||||
|
||||
auto &pair = m_textures[ Texture ];
|
||||
pair.second = m_garbagecollector.timestamp();
|
||||
@@ -1455,20 +1464,34 @@ texture_manager::mark_as_used(const texture_handle Texture) {
|
||||
}
|
||||
|
||||
void
|
||||
texture_manager::delete_textures() {
|
||||
texture_bank::delete_textures() {
|
||||
for( auto const &texture : m_textures ) {
|
||||
// usunięcie wszyskich tekstur (bez usuwania struktury)
|
||||
if( texture.first->id > 0
|
||||
&& texture.first->id != -1 ) {
|
||||
::glDeleteTextures( 1, &texture.first->id );
|
||||
}
|
||||
texture.first->destroy();
|
||||
delete texture.first;
|
||||
}
|
||||
m_textures.clear();
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::destroy() {
|
||||
|
||||
if( id > 0
|
||||
&& id != -1 ) {
|
||||
::glDeleteTextures( 1, &id );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opengl_texture::on_failed() {
|
||||
|
||||
// NOTE: temporary workaround for texture assignment errors: the texture counts as made, with no gl texture
|
||||
id = 0;
|
||||
}
|
||||
|
||||
// starts a scan for gl textures used only by vehicles far away
|
||||
void
|
||||
texture_manager::begin_release_scan() {
|
||||
texture_bank::begin_release_scan() {
|
||||
|
||||
m_releasescantime = std::chrono::steady_clock::now();
|
||||
// textures bound from now on are stamped with the time of this scan, the sweep may not be running
|
||||
@@ -1480,7 +1503,7 @@ texture_manager::begin_release_scan() {
|
||||
|
||||
// marks texture of a vehicle as needed if the vehicle is near, otherwise only as one used by vehicles
|
||||
void
|
||||
texture_manager::mark_as_needed( texture_handle const Texture, bool const Near ) {
|
||||
texture_bank::mark_as_needed( texture_handle const Texture, bool const Near ) {
|
||||
|
||||
if( ( Texture <= 0 )
|
||||
|| ( Texture >= static_cast<texture_handle>( m_neededtimes.size() ) ) ) {
|
||||
@@ -1506,7 +1529,7 @@ texture_manager::mark_as_needed( texture_handle const Texture, bool const Near )
|
||||
|
||||
// releases gl textures of vehicles not needed nor drawn for a while
|
||||
void
|
||||
texture_manager::release_unneeded() {
|
||||
texture_bank::release_unneeded() {
|
||||
|
||||
// the delay keeps textures of a vehicle moving back and forth around the release distance from going in and out
|
||||
auto const delay { std::chrono::seconds{ 10 } };
|
||||
@@ -1520,8 +1543,8 @@ texture_manager::release_unneeded() {
|
||||
}
|
||||
auto &record { m_textures[ index ] };
|
||||
auto &texture { *record.first };
|
||||
if( ( texture.id == static_cast<GLuint>( -1 ) )
|
||||
|| ( texture.id == 0 )
|
||||
if( ( false == texture.resident() )
|
||||
|| ( texture.get_id() == 0 )
|
||||
|| ( true == texture.is_static )
|
||||
|| ( true == texture.is_rendertarget )
|
||||
|| ( texture.type == "make:" )
|
||||
@@ -1539,26 +1562,30 @@ texture_manager::release_unneeded() {
|
||||
}
|
||||
if( releasecount > 0 ) {
|
||||
// released gl names can be given to new textures, the unit cache can't trust them
|
||||
for( auto &unit : opengl_texture::units ) {
|
||||
unit = -1;
|
||||
}
|
||||
released();
|
||||
}
|
||||
}
|
||||
|
||||
// performs a resource sweep
|
||||
void
|
||||
texture_manager::update() {
|
||||
texture_bank::update() {
|
||||
|
||||
if( m_garbagecollector.sweep() > 0 ) {
|
||||
for( auto &unit : opengl_texture::units ) {
|
||||
unit = -1;
|
||||
}
|
||||
released();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
texture_manager::released() {
|
||||
|
||||
for( auto &unit : opengl_texture::units ) {
|
||||
unit = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// what the textures keep in memory, for the debug panel
|
||||
texture_manager::memory_data
|
||||
texture_manager::memory() const {
|
||||
texture_bank::memory_data
|
||||
texture_bank::memory() const {
|
||||
|
||||
memory_data result;
|
||||
for( auto const &texture : m_textures ) {
|
||||
@@ -1567,7 +1594,7 @@ texture_manager::memory() const {
|
||||
++result.cpu.count;
|
||||
result.cpu.bytes += memory_of( texture.first->data );
|
||||
}
|
||||
if( texture.first->id != opengl_texture::invalid_id ) {
|
||||
if( true == texture.first->resident() ) {
|
||||
++result.gpu.count;
|
||||
result.gpu.bytes += static_cast<std::uint64_t>( texture.first->size ) * 1024;
|
||||
}
|
||||
@@ -1590,7 +1617,7 @@ texture_manager::memory() const {
|
||||
|
||||
// has the data of a texture read, if it's waiting for that
|
||||
void
|
||||
texture_manager::prefetch( texture_handle const Texture, glm::dvec3 const &Origin ) {
|
||||
texture_bank::prefetch( texture_handle const Texture, glm::dvec3 const &Origin ) {
|
||||
|
||||
if( ( Texture <= 0 )
|
||||
|| ( Texture >= static_cast<texture_handle>( m_textures.size() ) ) ) {
|
||||
@@ -1602,7 +1629,7 @@ texture_manager::prefetch( texture_handle const Texture, glm::dvec3 const &Origi
|
||||
// gives back the data read for textures which nothing drew within the specified time since it was asked for, or read ahead of the
|
||||
// camera which went farther than the specified distance from there since. it's read again when a texture is needed
|
||||
std::size_t
|
||||
texture_manager::drop_read_ahead( std::chrono::steady_clock::duration const Age, glm::dvec3 const &Camera, double const Distance ) {
|
||||
texture_bank::drop_read_ahead( std::chrono::steady_clock::duration const Age, glm::dvec3 const &Camera, double const Distance ) {
|
||||
|
||||
auto const now { std::chrono::steady_clock::now() };
|
||||
std::size_t count { 0 };
|
||||
@@ -1629,7 +1656,7 @@ texture_manager::drop_read_ahead( std::chrono::steady_clock::duration const Age,
|
||||
|
||||
// debug performance string
|
||||
std::string
|
||||
texture_manager::info() const {
|
||||
texture_bank::info() const {
|
||||
|
||||
// TODO: cache this data and update only during resource sweep
|
||||
std::size_t totaltexturecount{ m_textures.size() - 1 };
|
||||
@@ -1668,7 +1695,7 @@ texture_manager::info() const {
|
||||
|
||||
// checks whether specified texture is in the texture bank. returns texture id, or npos.
|
||||
texture_handle
|
||||
texture_manager::find_in_databank( std::string const &Texturename ) const {
|
||||
texture_bank::find_in_databank( std::string const &Texturename ) const {
|
||||
|
||||
std::vector<std::string> const filenames {
|
||||
Global.asCurrentTexturePath + Texturename,
|
||||
@@ -1687,7 +1714,7 @@ texture_manager::find_in_databank( std::string const &Texturename ) const {
|
||||
|
||||
// checks whether specified file exists.
|
||||
std::pair<std::string, std::string>
|
||||
texture_manager::find_on_disk( std::string const &Texturename ) {
|
||||
texture_bank::find_on_disk( std::string const &Texturename ) {
|
||||
|
||||
std::vector<std::string> const filenames {
|
||||
Global.asCurrentTexturePath + Texturename,
|
||||
|
||||
159
model/Texture.h
159
model/Texture.h
@@ -15,40 +15,33 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "winheaders.h"
|
||||
#include "utilities/memorystats.h"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include "model/ResourceManager.h"
|
||||
#include "gl/ubo.h"
|
||||
#include "interfaces/ITexture.h"
|
||||
|
||||
struct texture_request; // texture data read by a worker thread, with gfx.textures.streaming
|
||||
|
||||
struct opengl_texture : public ITexture {
|
||||
// a texture as its file gives it, whichever api draws it: read and decoded (dds, tga, png, bmp, jpg, ktx, tex), with the mipmaps
|
||||
// the file has, kept within maxtexturesize; with gfx.textures.streaming the data of a dds file is read by worker threads. the
|
||||
// data is laid out as opengl takes it (the bottom row first) and its formats are the values of opengl (GL_RGBA,
|
||||
// GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ...), which the renderers take as they are. a renderer makes its own object of the texture
|
||||
// from the data (create())
|
||||
struct texture_source : public ITexture {
|
||||
static DDSURFACEDESC2 deserialize_ddsd(std::istream&);
|
||||
static DDCOLORKEY deserialize_ddck(std::istream&);
|
||||
static DDPIXELFORMAT deserialize_ddpf(std::istream&);
|
||||
static DDSCAPS2 deserialize_ddscaps(std::istream&);
|
||||
|
||||
// constructors
|
||||
opengl_texture() = default;
|
||||
texture_source() = default;
|
||||
// methods
|
||||
void
|
||||
load();
|
||||
bool
|
||||
bind( size_t unit );
|
||||
static void
|
||||
unbind( size_t unit );
|
||||
virtual bool
|
||||
create( bool const Static = false ) override;
|
||||
// releases resources allocated on the opengl end, storing local copy if requested
|
||||
void
|
||||
release() override;
|
||||
void
|
||||
make_stub() override;
|
||||
void
|
||||
alloc_rendertarget( GLint format, GLint components, int width, int height, int layers = 1, int samples = 1, GLint wrap = GL_CLAMP_TO_EDGE );
|
||||
virtual void
|
||||
set_components_hint( GLint hint ) override;
|
||||
static void
|
||||
reset_unit_cache();
|
||||
virtual int
|
||||
get_width() const override {
|
||||
return data_width; }
|
||||
@@ -57,10 +50,6 @@ struct opengl_texture : public ITexture {
|
||||
get_height() const override {
|
||||
return data_height; }
|
||||
virtual
|
||||
size_t
|
||||
get_id() const override {
|
||||
return id; }
|
||||
virtual
|
||||
bool
|
||||
is_stub() const override {
|
||||
return is_texstub; }
|
||||
@@ -86,11 +75,15 @@ struct opengl_texture : public ITexture {
|
||||
return type; }
|
||||
|
||||
virtual void make_from_memory(size_t width, size_t height, const uint8_t *data) override;
|
||||
virtual void update_from_memory(size_t width, size_t height, const uint8_t *data) override;
|
||||
|
||||
// whether the texture has its object made by the renderer (it may be the failed one, with the id 0)
|
||||
virtual bool
|
||||
resident() const = 0;
|
||||
// the object of the renderer goes, with the bank of the textures
|
||||
virtual void
|
||||
destroy() = 0;
|
||||
|
||||
// members
|
||||
static constexpr GLuint invalid_id { std::numeric_limits<GLuint>::max() }; // id value of texture without GL resource
|
||||
GLuint id{ invalid_id }; // associated GL resource
|
||||
bool has_alpha{ false }; // indicates the texture has alpha channel
|
||||
bool is_ready{ false }; // indicates the texture was processed and is ready for use
|
||||
std::string traits; // requested texture attributes: wrapping modes etc
|
||||
@@ -99,10 +92,6 @@ struct opengl_texture : public ITexture {
|
||||
std::size_t size{ 0 }; // size of the texture data, in kb
|
||||
GLint components_hint = 0; // components that material wants
|
||||
|
||||
GLenum target = GL_TEXTURE_2D;
|
||||
static std::array<GLuint, gl::MAX_TEXTURES + gl::HELPER_TEXTURES> units;
|
||||
static GLint m_activeunit;
|
||||
|
||||
public:
|
||||
// methods
|
||||
void make_request();
|
||||
@@ -112,7 +101,6 @@ public:
|
||||
void load_TEX();
|
||||
void load_STBI();
|
||||
void load_TGA();
|
||||
void set_filtering() const;
|
||||
void downsize( GLuint const Format );
|
||||
void flip_vertical();
|
||||
|
||||
@@ -129,8 +117,6 @@ public:
|
||||
bool reload_on_use = false; // the data was dropped along with the gl texture of a far texture, it's read again when the texture is needed
|
||||
bool is_static = false; // is excluded from garbage collection
|
||||
bool is_rendertarget = false; // is used as postfx rendertarget, without loaded data
|
||||
int samples = 1;
|
||||
int layers = 1;
|
||||
bool is_texstub = false; // for make_from_memory internal_src: functionality
|
||||
std::vector<unsigned char> data; // texture data (stored GL-style, bottom-left origin)
|
||||
resource_state data_state{ resource_state::none }; // current state of texture data
|
||||
@@ -140,36 +126,90 @@ public:
|
||||
GLint data_format{ 0 },
|
||||
data_components{ 0 };
|
||||
GLint data_type = GL_UNSIGNED_BYTE;
|
||||
GLint wrap_mode_s = GL_REPEAT;
|
||||
GLint wrap_mode_t = GL_REPEAT;
|
||||
/*
|
||||
std::atomic<bool> is_loaded{ false }; // indicates the texture data was loaded and can be processed
|
||||
std::atomic<bool> is_good{ false }; // indicates the texture data was retrieved without errors
|
||||
*/
|
||||
// the compressed formats the files give, with the bytes of their blocks of 4x4 texels
|
||||
static std::unordered_map<GLint, int> precompressed_formats;
|
||||
static std::unordered_map<GLint, GLint> drivercompressed_formats;
|
||||
static std::unordered_map<GLint, std::unordered_map<GLint, GLint>> mapping;
|
||||
|
||||
protected:
|
||||
// the data of the texture couldn't be read (load(), complete_data())
|
||||
virtual void
|
||||
on_failed() {}
|
||||
};
|
||||
|
||||
class texture_manager {
|
||||
// a texture of the opengl renderer
|
||||
struct opengl_texture : public texture_source {
|
||||
// constructors
|
||||
opengl_texture() = default;
|
||||
// methods
|
||||
bool
|
||||
bind( size_t unit );
|
||||
static void
|
||||
unbind( size_t unit );
|
||||
virtual bool
|
||||
create( bool const Static = false ) override;
|
||||
// releases resources allocated on the opengl end, storing local copy if requested
|
||||
void
|
||||
release() override;
|
||||
void
|
||||
alloc_rendertarget( GLint format, GLint components, int width, int height, int layers = 1, int samples = 1, GLint wrap = GL_CLAMP_TO_EDGE );
|
||||
static void
|
||||
reset_unit_cache();
|
||||
virtual
|
||||
size_t
|
||||
get_id() const override {
|
||||
return id; }
|
||||
virtual void update_from_memory(size_t width, size_t height, const uint8_t *data) override;
|
||||
bool
|
||||
resident() const override {
|
||||
return id != invalid_id; }
|
||||
void
|
||||
destroy() override;
|
||||
|
||||
// members
|
||||
static constexpr GLuint invalid_id { std::numeric_limits<GLuint>::max() }; // id value of texture without GL resource
|
||||
GLuint id{ invalid_id }; // associated GL resource
|
||||
|
||||
GLenum target = GL_TEXTURE_2D;
|
||||
static std::array<GLuint, gl::MAX_TEXTURES + gl::HELPER_TEXTURES> units;
|
||||
static GLint m_activeunit;
|
||||
|
||||
public:
|
||||
texture_manager();
|
||||
~texture_manager() { delete_textures(); }
|
||||
// methods
|
||||
void set_filtering() const;
|
||||
|
||||
// activates specified texture unit
|
||||
// members
|
||||
int samples = 1;
|
||||
int layers = 1;
|
||||
GLint wrap_mode_s = GL_REPEAT;
|
||||
GLint wrap_mode_t = GL_REPEAT;
|
||||
|
||||
static std::unordered_map<GLint, GLint> drivercompressed_formats;
|
||||
static std::unordered_map<GLint, std::unordered_map<GLint, GLint>> mapping;
|
||||
|
||||
protected:
|
||||
void
|
||||
unit( GLint const Textureunit );
|
||||
on_failed() override;
|
||||
};
|
||||
|
||||
// the textures of a renderer: made from their files the first time they are asked for, given back by their handles, released
|
||||
// when nothing used them for a while (gfx.resource.sweep) or when only vehicles far away use them (gfx.textures.releasedistance).
|
||||
// the objects of the textures come from the renderer (the function given to the constructor)
|
||||
class texture_bank {
|
||||
|
||||
public:
|
||||
explicit texture_bank( std::function<texture_source *()> Make );
|
||||
virtual ~texture_bank();
|
||||
|
||||
// creates texture object out of data stored in specified file
|
||||
texture_handle
|
||||
create( std::string Filename, bool const Loadnow = true, GLint Formathint = GL_SRGB_ALPHA );
|
||||
// binds specified texture to specified texture unit
|
||||
void
|
||||
bind( std::size_t const Unit, texture_handle const Texture );
|
||||
opengl_texture &
|
||||
texture_source &
|
||||
mark_as_used( texture_handle const Texture );
|
||||
// provides direct access to specified texture object
|
||||
opengl_texture &
|
||||
texture_source &
|
||||
texture( texture_handle const Texture ) const { return *m_textures[Texture].first; }
|
||||
// performs a resource sweep
|
||||
void
|
||||
@@ -208,10 +248,15 @@ public:
|
||||
std::size_t
|
||||
drop_read_ahead( std::chrono::steady_clock::duration const Age, glm::dvec3 const &Camera, double const Distance );
|
||||
|
||||
protected:
|
||||
// objects of textures were released, the renderer can't trust what it knew of their names
|
||||
virtual void
|
||||
released() {}
|
||||
|
||||
private:
|
||||
// types:
|
||||
typedef std::pair<
|
||||
opengl_texture *,
|
||||
texture_source *,
|
||||
resource_timestamp > texturetimepoint_pair;
|
||||
|
||||
typedef std::vector< texturetimepoint_pair > texturetimepointpair_sequence;
|
||||
@@ -233,6 +278,7 @@ private:
|
||||
delete_textures();
|
||||
|
||||
// members:
|
||||
std::function<texture_source *()> m_make;
|
||||
texture_handle const npos { 0 }; // should be -1, but the rest of the code uses -1 for something else
|
||||
texturetimepointpair_sequence m_textures;
|
||||
index_map m_texturemappings;
|
||||
@@ -241,6 +287,31 @@ private:
|
||||
garbage_collector<texturetimepointpair_sequence> m_garbagecollector { m_textures, 600, 60, "texture" };
|
||||
};
|
||||
|
||||
// the textures of the opengl renderer
|
||||
class texture_manager : public texture_bank {
|
||||
|
||||
public:
|
||||
texture_manager();
|
||||
|
||||
// activates specified texture unit
|
||||
void
|
||||
unit( GLint const Textureunit );
|
||||
// binds specified texture to specified texture unit
|
||||
void
|
||||
bind( std::size_t const Unit, texture_handle const Texture );
|
||||
opengl_texture &
|
||||
mark_as_used( texture_handle const Texture ) {
|
||||
return static_cast<opengl_texture &>( texture_bank::mark_as_used( Texture ) ); }
|
||||
// provides direct access to specified texture object
|
||||
opengl_texture &
|
||||
texture( texture_handle const Texture ) const {
|
||||
return static_cast<opengl_texture &>( texture_bank::texture( Texture ) ); }
|
||||
|
||||
protected:
|
||||
void
|
||||
released() override;
|
||||
};
|
||||
|
||||
// reduces provided data image to half of original size, using basic 2x2 average
|
||||
template <typename Colortype_>
|
||||
void
|
||||
|
||||
@@ -204,7 +204,7 @@ void opengl_material::finalize(bool Loadnow)
|
||||
key.pop_back();
|
||||
if (shader->param_conf.find(key) != shader->param_conf.end())
|
||||
{
|
||||
gl::shader::param_entry entry = shader->param_conf[key];
|
||||
gfx::shader_param_entry entry = shader->param_conf[key];
|
||||
for (size_t i = 0; i < entry.size; i++)
|
||||
params[entry.location][entry.offset + i] = value[i];
|
||||
}
|
||||
@@ -242,17 +242,17 @@ void opengl_material::finalize(bool Loadnow)
|
||||
|
||||
for (auto it : shader->param_conf)
|
||||
{
|
||||
gl::shader::param_entry entry = it.second;
|
||||
gfx::shader_param_entry entry = it.second;
|
||||
if (std::isnan(params[entry.location][entry.offset]))
|
||||
{
|
||||
float value = std::numeric_limits<float>::quiet_NaN();
|
||||
if (entry.defaultparam == gl::shader::defaultparam_e::one)
|
||||
if (entry.defaultparam == gfx::shader_param_default::one)
|
||||
value = 1.0f;
|
||||
else if (entry.defaultparam == gl::shader::defaultparam_e::zero)
|
||||
else if (entry.defaultparam == gfx::shader_param_default::zero)
|
||||
value = 0.0f;
|
||||
else if (entry.defaultparam == gl::shader::defaultparam_e::required)
|
||||
else if (entry.defaultparam == gfx::shader_param_default::required)
|
||||
log_error("unspecified required param: " + it.first);
|
||||
else if (entry.defaultparam != gl::shader::defaultparam_e::nan)
|
||||
else if (entry.defaultparam != gfx::shader_param_default::nan)
|
||||
{
|
||||
params_state.push_back(entry);
|
||||
continue;
|
||||
@@ -265,7 +265,7 @@ void opengl_material::finalize(bool Loadnow)
|
||||
|
||||
for (auto it : shader->texture_conf)
|
||||
{
|
||||
gl::shader::texture_entry &entry = it.second;
|
||||
gfx::shader_texture_entry &entry = it.second;
|
||||
texture_handle handle = textures[entry.id];
|
||||
// NOTE: texture validation at this stage relies on forced texture load behaviour during its create() call
|
||||
// TODO: move texture id validation to later stage if/when deferred texture loading is implemented
|
||||
@@ -302,7 +302,7 @@ bool opengl_material::update() {
|
||||
finalize( true );
|
||||
result = true;
|
||||
}
|
||||
catch( gl::shader_exception const &e ) {
|
||||
catch( gfx::shader_exception const &e ) {
|
||||
ErrorLog( "invalid shader: " + std::string( e.what() ) );
|
||||
}
|
||||
}
|
||||
@@ -434,7 +434,7 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
|
||||
shader = GfxRenderer->Fetch_Shader(value);
|
||||
m_shader_priority = Priority;
|
||||
}
|
||||
catch (gl::shader_exception const &e)
|
||||
catch (gfx::shader_exception const &e)
|
||||
{
|
||||
log_error("invalid shader: " + std::string(e.what()));
|
||||
}
|
||||
@@ -591,7 +591,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
{
|
||||
material.shader = GfxRenderer->Fetch_Shader("default_1");
|
||||
}
|
||||
catch (gl::shader_exception const &e)
|
||||
catch (gfx::shader_exception const &e)
|
||||
{
|
||||
ErrorLog("invalid shader: " + std::string(e.what()));
|
||||
}
|
||||
@@ -625,7 +625,7 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
|
||||
materialhandle = m_materials.size();
|
||||
m_materials.emplace_back( std::move(material) );
|
||||
m_materialmappings.emplace( m_materials.back().name, materialhandle );
|
||||
} catch (gl::shader_exception const &e) {
|
||||
} catch (gfx::shader_exception const &e) {
|
||||
ErrorLog("invalid shader: " + std::string(e.what()));
|
||||
// record the failure so subsequent Fetch_Material(filename) calls
|
||||
// short-circuit without re-running the failing compile.
|
||||
@@ -652,7 +652,7 @@ material_manager::create_from_text( std::string const &Name, std::string const &
|
||||
try {
|
||||
material.finalize( true );
|
||||
}
|
||||
catch( gl::shader_exception const &e ) {
|
||||
catch( gfx::shader_exception const &e ) {
|
||||
ErrorLog( "invalid shader: " + std::string( e.what() ) );
|
||||
return null_handle;
|
||||
}
|
||||
@@ -709,7 +709,7 @@ material_manager::create_matte( material_handle const Material ) {
|
||||
matte.params_state.erase(
|
||||
std::remove_if(
|
||||
std::begin( matte.params_state ), std::end( matte.params_state ),
|
||||
[&]( gl::shader::param_entry const &State ) {
|
||||
[&]( gfx::shader_param_entry const &State ) {
|
||||
return State.location == entry->second.location && State.offset == entry->second.offset; } ),
|
||||
std::end( matte.params_state ) );
|
||||
}
|
||||
@@ -747,7 +747,7 @@ material_manager::create_tinted( material_handle const Material, glm::vec3 const
|
||||
tinted.params_state.erase(
|
||||
std::remove_if(
|
||||
std::begin( tinted.params_state ), std::end( tinted.params_state ),
|
||||
[&]( gl::shader::param_entry const &State ) {
|
||||
[&]( gfx::shader_param_entry const &State ) {
|
||||
return State.location == location; } ),
|
||||
std::end( tinted.params_state ) );
|
||||
auto const tintedhandle { static_cast<material_handle>( m_materials.size() ) };
|
||||
@@ -832,7 +832,7 @@ material_manager::blend_lighting( material_handle const Material ) {
|
||||
result = ( fits ? lighting : -1 );
|
||||
}
|
||||
}
|
||||
catch( gl::shader_exception const &e ) {
|
||||
catch( gfx::shader_exception const &e ) {
|
||||
ErrorLog( "invalid shader: " + std::string( e.what() ) );
|
||||
}
|
||||
}
|
||||
@@ -914,7 +914,7 @@ material_manager::build_blend( blend_key const &Key, opengl_material &Blend ) {
|
||||
Blend.finalize( true );
|
||||
return Blend.is_good;
|
||||
}
|
||||
catch( gl::shader_exception const &e ) {
|
||||
catch( gfx::shader_exception const &e ) {
|
||||
ErrorLog( "invalid shader: " + std::string( e.what() ) );
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -12,7 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "interfaces/IMaterial.h"
|
||||
#include "utilities/Classes.h"
|
||||
#include "model/Texture.h"
|
||||
#include "gl/shader.h"
|
||||
#include "rendering/common/shadersource.h"
|
||||
#include "gl/ubo.h"
|
||||
|
||||
// a collection of parameters for the rendering setup.
|
||||
@@ -26,9 +26,9 @@ struct opengl_material : public IMaterial {
|
||||
// NOTE: all variants share the remaining material properties, opacity and translucency included
|
||||
std::vector<texture_set> texture_variants;
|
||||
std::array<glm::vec4, gl::MAX_PARAMS> params;
|
||||
std::vector<gl::shader::param_entry> params_state;
|
||||
std::vector<gfx::shader_param_entry> params_state;
|
||||
|
||||
std::shared_ptr<gl::program> shader;
|
||||
std::shared_ptr<gfx::shader_program> shader;
|
||||
std::optional<float> opacity;
|
||||
std::optional<float> selfillum;
|
||||
float glossiness { 10.f };
|
||||
|
||||
Reference in New Issue
Block a user