Compare commits

..
Author SHA1 Message Date
SirKnightly 2b57379fed Automated build commit 2026-11-03 01:27:32 +00:00
169 changed files with 638 additions and 3989 deletions

No files matched your search

+4 -13
View File
@@ -57,15 +57,6 @@ endif()
PROJECT(FS2_Open LANGUAGES ${FSO_LANGUAGES})
if (ANDROID)
message(STATUS "Building for Android (NDK)")
set(FSO_BUILD_INCLUDED_LIBS ON CACHE BOOL "" FORCE)
set(USING_PREBUILT_LIBS ON CACHE BOOL "" FORCE)
set(SDL3_USE_PRECOMPILED ON CACHE BOOL "" FORCE)
set(OPENAL_USE_PRECOMPILED ON CACHE BOOL "" FORCE)
set(USING_PREBUILT_VULKAN ON CACHE BOOL "" FORCE)
endif()
# Check if the external modules exists
IF(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib/libRocket/Build")
message(FATAL_ERROR "External submodules could not be found. Please make sure you have updated your submodules.")
@@ -118,8 +109,8 @@ OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
IF(WIN32 OR APPLE OR ANDROID)
# On windows, mac and android the default should be to always build the included libraries
IF(WIN32 OR APPLE)
# On windows and mac the default should be to always build the included libraries
SET(FSO_BUILD_INCLUDED_LIBS_DEFAULT ON)
ELSE()
SET(FSO_BUILD_INCLUDED_LIBS_DEFAULT OFF)
@@ -147,13 +138,13 @@ OPTION(FSO_BUILD_WITH_DISCORD "Build with Discord support" ON)
OPTION(FSO_BUILD_WITH_OPENGL "Enable compilation of the OpenGL renderer" ON)
OPTION(FSO_BUILD_WITH_OPENGL_DEBUG "Enables debug option for OpenGL" OFF)
OPTION(FSO_BUILD_WITH_OPENGL_ES "When building OpenGL, use OpenGL ES compatibility layer" OFF)
OPTION(FSO_BUILD_WITH_OPENGL_ES "When building OpenGL, use OpenGL ES compatibility layer (External shaders only!)" OFF)
OPTION(FSO_BUILD_WITH_VULKAN "Enable compilation of the Vulkan renderer" ON)
if(NOT FSO_BUILD_WITH_OPENGL AND FSO_BUILD_WITH_OPENGL_ES)
# Disable GLES if not building with OpenGL
set(FSO_BUILD_WITH_OPENGL_ES OFF CACHE BOOL "" FORCE)
set(FSO_BUILD_WITH_OPENGL_ES OFF FORCE)
endif()
+1 -1
View File
@@ -7,7 +7,7 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 26)
set_if_not_defined(FSO_VERSION_MINOR 3)
set_if_not_defined(FSO_VERSION_MINOR 1)
set_if_not_defined(FSO_VERSION_BUILD 0)
# A numeric revision e.g. the CI build number
+1 -1
View File
@@ -1693,7 +1693,7 @@ static void asteroid_do_area_effect(object *asteroid_objp)
if ( weapon_area_calc_damage(ship_objp, &asteroid_objp->pos, asip->inner_rad, asip->outer_rad, asip->blast, asip->damage, &blast, &damage, asip->outer_rad) == -1 )
continue;
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx, DamageSource::Explosion);
ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage, asip->damage_type_idx);
weapon_area_apply_blast(nullptr, ship_objp, &asteroid_objp->pos, blast, false);
} // end for
}
-7
View File
@@ -1036,13 +1036,6 @@ void bm_init() {
bm_inited = true;
}
bool bm_is_cubemap(int handle)
{
const BM_TYPE type = bm_get_entry(handle)->comp_type;
return type == BM_TYPE_CUBEMAP_DDS || type == BM_TYPE_CUBEMAP_DXT1 || type == BM_TYPE_CUBEMAP_DXT3 ||
type == BM_TYPE_CUBEMAP_DXT5;
}
int bm_is_compressed(int num) {
auto entry = bm_get_entry(num);
BM_TYPE type = BM_TYPE_NONE;
-8
View File
@@ -594,14 +594,6 @@ void bm_get_components(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a);
*/
int bm_is_compressed(int handle);
/**
* @brief Returns true if the bitmap indexed by handle was loaded from a cubemap image file
*
* @note Render targets return false, even cubemap ones, and so do BC7 (DX10) DDS cubemaps, whose cube flag the DDS
* loader does not keep
*/
bool bm_is_cubemap(int handle);
/**
* @brief Gets the correct TCACHE_TYPE for compressed graphics (uncompressed are assumed TCACHE_TYPE_NORMAL)
*/
+15 -90
View File
@@ -33,7 +33,7 @@
#include "parse/encrypt.h"
#include "cfilesystem.h"
#include <algorithm>
#include <limits>
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
@@ -185,12 +185,7 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
char buf[CFILE_ROOT_DIRECTORY_LEN];
#ifndef __ANDROID__
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
#else
(void)exe_dir;
strncpy(buf, os_android_get_working_folder_path().c_str(), CFILE_ROOT_DIRECTORY_LEN - 1);
#endif
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
buf[CFILE_ROOT_DIRECTORY_LEN - 1] = '\0';
@@ -1110,98 +1105,28 @@ void cfread_string(char *buf, int n, CFILE *file)
} while (c != 0 );
}
namespace {
struct string_len_header {
int len = 0;
int stored = 0;
int start = 0;
bool length_cut = false;
};
// a past-the-end length is clamped like any cfread, but a negative one has nothing to clamp to, so inside a
// limited section it throws and the loader skips the rest of the section
string_len_header read_string_len_header(CFILE* file)
void cfread_string_len(char *buf, int buffer_size, CFILE *file)
{
string_len_header h;
if (!cf_is_valid(file)) {
return h;
int len;
len = cfread_int(file);
Assertion( (len <= buffer_size), "String cannot fit in buffer, len: %i, buffer: %i", len, buffer_size);
if (len) {
cfread(buf, len, 1, file);
Assertion(len != buffer_size || buf[len - 1] == 0, "Unterminated string does not fit in buffer");
}
int before = cftell(file);
h.length_cut = cfread(&h.len, sizeof(h.len), 1, file) != 1;
h.start = cftell(file);
if (h.length_cut) {
// a clean end of file reads as an empty string without a warning, as cfread_int does
h.length_cut = (h.start != before) || (cfeof(file) == 0);
return h;
}
h.len = INTEL_INT(h.len);
if ((h.len < 0) && (file->max_read_len != 0)) {
throw cfile::max_read_length("Attempted to read a string of negative length " + std::to_string(h.len));
}
h.stored = static_cast<int>(cf_check_read_size(file, static_cast<size_t>(std::max(h.len, 0))));
return h;
}
// reads count of the stored characters and leaves the file just past the whole string; false if the read failed
bool read_string_len_body(const string_len_header& h, char* dest, int count, CFILE* file)
{
bool ok = (count <= 0) || (cfread(dest, count, 1, file) == 1);
if (!ok || (h.stored > count)) {
cfseek(file, h.start + h.stored, CF_SEEK_SET);
}
return ok;
}
// warned last, so the file position is right even if a debug build stops here
void warn_string_len(const string_len_header& h, bool read_ok, bool cut, int buffer_size, CFILE* file)
{
if (h.length_cut) {
Warning(LOCATION, "cfread_string_len: cut-off string length field in %s", cf_get_filename(file));
} else if (!read_ok) {
Warning(LOCATION,
"cfread_string_len: could not read a string of %d characters in %s",
h.stored,
cf_get_filename(file));
} else if (h.len != h.stored) {
Warning(LOCATION, "cfread_string_len: corrupt string length %d in %s", h.len, cf_get_filename(file));
} else if (cut) {
Warning(LOCATION,
"cfread_string_len: a string of %d bytes was cut to fit a buffer of %d in %s",
h.len,
buffer_size,
cf_get_filename(file));
}
}
} // namespace
void cfread_string_len(char* buf, int buffer_size, CFILE* file)
{
Assertion(buffer_size > 0, "cfread_string_len needs room for at least the terminator, buffer: %i", buffer_size);
string_len_header h = read_string_len_header(file);
if (buffer_size <= 0) {
bool read_ok = read_string_len_body(h, buf, 0, file);
warn_string_len(h, read_ok, h.stored > 0, buffer_size, file);
return;
}
int count = std::min(h.stored, buffer_size);
bool read_ok = read_string_len_body(h, buf, count, file);
int kept = read_ok ? count : 0;
bool cut = (kept == buffer_size) && (memchr(buf, 0, buffer_size) == nullptr);
buf[std::min(kept, buffer_size - 1)] = 0;
warn_string_len(h, read_ok, cut, buffer_size, file);
buf[MIN(len, buffer_size - 1)] = 0;
}
SCP_string cfread_string_len(CFILE *file)
{
string_len_header h = read_string_len_header(file);
int len = cfread_int(file);
SCP_string str;
str.resize(h.stored);
bool read_ok = read_string_len_body(h, str.data(), h.stored, file);
if (!read_ok) {
str.clear();
}
warn_string_len(h, read_ok, false, 0, file);
str.resize(len);
if (len)
cfread(&str[0], len, 1, file);
return str;
}
+2 -8
View File
@@ -320,26 +320,20 @@ void cfread_string(char *buf,int n, CFILE *file);
/**
* @brief Read a fixed length string that is not null-terminated, with the length stored in file.
*
* Keeps at most buffer_size - 1 characters and leaves the file just past the whole string, unless it throws.
*
* If it is not null-terminated, the length of the string *must* be less than the size of the buffer (to make room for one)
*
* @param buf Pre-allocated array to store string
* @param buffer_size Size of pre-allocated array
* @param file File to read from
*
* @note Appends NULL character to string (buf)
* @note Bad data gets a warning; at a clean end of file, or with an invalid file, the string is empty and nothing is
* warned. Inside a limited section (cf_set_max_read_len), a negative length, or a read that still passes the limit
* once clamped to the end of the file, throws cfile::max_read_length.
*/
void cfread_string_len(char *buf,int buffer_size, CFILE *file);
/**
* @brief Read a string from the file where the length is stored in the file
*
* @param file The file to read the string from
* @return The string that was read
*
* @note Warns and throws like the char* overload, except that nothing is cut.
*/
SCP_string cfread_string_len(CFILE *file);
+14 -24
View File
@@ -193,8 +193,21 @@ int cfseek( CFILE *cfile, int offset, int where )
}
size_t cf_check_read_size(CFILE* cfile, size_t size)
// cfread() reads from a file
//
// returns: returns the number of full elements read
//
//
int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
{
if(!cf_is_valid(cfile))
return 0;
size_t size = elsize*nelem;
if(buf == NULL || size <= 0)
return 0;
if ( (cfile->raw_position+size) > cfile->size ) {
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
size = cfile->size - cfile->raw_position;
@@ -213,29 +226,6 @@ size_t cf_check_read_size(CFILE* cfile, size_t size)
}
}
return size;
}
// cfread() reads from a file
//
// returns: returns the number of full elements read
//
//
int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
{
if(!cf_is_valid(cfile))
return 0;
size_t size = elsize*nelem;
if(buf == nullptr || size <= 0)
return 0;
size = cf_check_read_size(cfile, size);
if (size < 1) {
return 0;
}
size_t bytes_read;
if (cfile->data != nullptr) {
// This is a file from memory
-5
View File
@@ -62,9 +62,4 @@ void cf_check_compression(CFILE* cfile);
// Used to clear compression info data and free dynamic memory used by compression
void cf_clear_compression_info(CFILE* cfile);
// Clamps a read of size bytes to the end of the file and returns the clamped size, or 0 at the end of the file
// without checking the limit; throws cfile::max_read_length if the clamped read would pass the file's read limit
// (cf_set_max_read_len).
size_t cf_check_read_size(CFILE* cfile, size_t size);
#endif
+50 -85
View File
@@ -75,7 +75,6 @@ const char *cmdline_arg_types[] =
enum class flag_output_type {
Binary,
Json_V1,
Json_V2,
};
// variables
@@ -556,12 +555,7 @@ int Cmdline_show_pos = 0;
int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
bool Cmdline_window = false;
#ifdef __ANDROID__
// Default to borderless in the legacy window-mode path as well.
bool Cmdline_fullscreen_window = true;
#else
bool Cmdline_fullscreen_window = false;
#endif
std::optional<std::pair<uint16_t, uint16_t>>Cmdline_window_res = std::nullopt;
char *Cmdline_res = 0;
char *Cmdline_center_res = 0;
@@ -1364,58 +1358,51 @@ static void handle_unix_modlist(char **modlist, size_t *len)
// external entry point into this modules
static void json_add_version(json_t* root) {
auto version_obj = json_object();
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
json_object_set_new(root, "version", version_obj);
}
static void json_add_easy_flags(json_t* root) {
auto easy_array = json_array();
for (auto& easy_flag : easy_flags) {
json_array_append_new(easy_array, json_string(easy_flag.name));
}
json_object_set_new(root, "easy_flags", easy_array);
}
static void json_add_flags(json_t* root) {
auto flags_array = json_array();
for (auto& flag : exe_params) {
auto flag_obj = json_object();
json_object_set_new(flag_obj, "name", json_string(flag.name));
json_object_set_new(flag_obj, "description", json_string(flag.desc));
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
json_object_set_new(flag_obj, "type", json_string(flag.type));
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
json_array_append_new(flags_array, flag_obj);
}
json_object_set_new(root, "flags", flags_array);
}
static json_t* json_get_v1() {
auto root = json_object();
json_add_version(root);
json_add_easy_flags(root);
json_add_flags(root);
{
auto version_obj = json_object();
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
json_object_set_new(root, "version", version_obj);
}
{
auto easy_array = json_array();
for (auto& easy_flag : easy_flags) {
json_array_append_new(easy_array, json_string(easy_flag.name));
}
json_object_set_new(root, "easy_flags", easy_array);
}
{
auto flags_array = json_array();
for (auto& flag : exe_params) {
auto flag_obj = json_object();
json_object_set_new(flag_obj, "name", json_string(flag.name));
json_object_set_new(flag_obj, "description", json_string(flag.desc));
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
json_object_set_new(flag_obj, "type", json_string(flag.type));
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
json_array_append_new(flags_array, flag_obj);
}
json_object_set_new(root, "flags", flags_array);
}
{
auto caps_array = json_array();
@@ -1526,19 +1513,6 @@ static json_t* json_get_v1() {
return root;
}
// json_v2 reports version, supported flags, and the preferences path for launchers,
// without querying graphics, audio, or joystick devices.
static json_t* json_get_v2() {
auto root = json_object();
json_add_version(root);
json_add_easy_flags(root);
json_add_flags(root);
json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
return root;
}
static void write_flags_file() {
FILE *fp = fopen("flags.lch","w");
@@ -1596,8 +1570,6 @@ static flag_output_type get_flags_output_type() {
return flag_output_type::Binary;
} else if (type == "json_v1") {
return flag_output_type::Json_V1;
} else if (type == "json_v2") {
return flag_output_type::Json_V2;
} else {
// This is supposed to make it easy for the launcher to recognize an unsupported type
printf("OUTPUT TYPE NOT SUPPORTED!\n");
@@ -1608,23 +1580,17 @@ static flag_output_type get_flags_output_type() {
static void write_flags() {
auto type = get_flags_output_type();
if (type == flag_output_type::Binary) {
switch(type) {
case flag_output_type::Binary:
write_flags_file();
return;
break;
case flag_output_type::Json_V1:
json_t* root = json_get_v1();
json_dumpf(root, stdout, JSON_INDENT(4));
json_decref(root);
break;
}
json_t* root = (type == flag_output_type::Json_V1) ? json_get_v1() : json_get_v2();
#ifdef __ANDROID__
char* dumped = json_dumps(root, JSON_INDENT(4));
os_android_set_flags_string(dumped ? dumped : "");
free(dumped);
#else
json_dumpf(root, stdout, JSON_INDENT(4));
#endif
json_decref(root);
}
bool SetCmdlineParams()
@@ -1821,7 +1787,6 @@ bool SetCmdlineParams()
options::OptionsManager::instance()->setOverride("Graphics.WindowMode",
std::unique_ptr<json_t>(json_integer(static_cast<int>(os::ViewportState::Windowed))), "-window");
Cmdline_window = true;
Cmdline_fullscreen_window = false;
}
if ( fullscreen_window_arg.found( ) )
+15 -11
View File
@@ -1322,7 +1322,7 @@ bool control_config_accept(bool API_Access)
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [str](CC_preset& p) {
return ((p.name == str) && ((p.get_type() == Preset_t::tbl) || (p.get_type() == Preset_t::hardcode)));
return ((p.name == str) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode)));
});
if (it != Control_config_presets.end()) {
@@ -1353,14 +1353,15 @@ bool control_config_accept(bool API_Access)
}
// Pack the current bindings into a preset, then save the file
CC_preset preset(std::move(str), Preset_t::pst);
CC_preset preset;
preset.name = std::move(str);
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
Control_config_presets.push_back(preset);
save_preset_file(preset, true);
// Reload the presets from file. Do this instead of just pushing the preset to the vector direct to get
// consistant ordering
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files();
// finally, save the new preset so that changes will get saved to this preset
@@ -1777,7 +1778,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
return (p.name == newName) && ((p.get_type() == Preset_t::tbl) || (p.get_type() == Preset_t::hardcode));
return (p.name == newName) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode));
});
if (it != Control_config_presets.end()) {
@@ -1790,7 +1791,9 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
}
// Pack the current bindings into a preset, then save the file
CC_preset preset(newName, Preset_t::pst);
CC_preset preset;
preset.name = newName;
preset.type = Preset_t::pst;
std::copy(Control_config.begin(), Control_config.end(), std::back_inserter(preset.bindings));
// Done with the file
@@ -1802,7 +1805,7 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
save_preset_file(preset, true);
// Reload the presets from file.
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files(newName);
// use the newly created preset
@@ -1810,9 +1813,10 @@ bool control_config_create_new_preset(const SCP_string& newName, bool overwrite)
return true;
} else if ((clone->name != preset.name) || (clone->get_type() != Preset_t::pst)) {
} else if ((clone->name != preset.name) || (clone->type != Preset_t::pst)) {
// Complain and ignore if the preset names or the type differs
return false;
}
return false; //should be unreachable, but just in case
@@ -1822,7 +1826,7 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
// Check if a hardcoded preset with name already exists. If so, complain to user and force retry
auto it = std::find_if(Control_config_presets.begin(), Control_config_presets.end(), [newName](CC_preset& p) {
return (p.name == newName) && ((p.get_type() == Preset_t::tbl) || (p.get_type() == Preset_t::hardcode));
return (p.name == newName) && ((p.type == Preset_t::tbl) || (p.type == Preset_t::hardcode));
});
if (it != Control_config_presets.end()) {
@@ -1834,13 +1838,13 @@ bool control_config_clone_preset(const CC_preset& preset, const SCP_string& newN
return false;
}
CC_preset newPreset(newName, Preset_t::pst);
newPreset.bindings = preset.bindings;
CC_preset newPreset = preset;
newPreset.name = newName;
bool success = save_preset_file(newPreset, false);
// Reload the presets from file.
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files(newName);
// use the newly cloned preset
+10 -18
View File
@@ -572,28 +572,20 @@ public:
* A preset, a collection of bindings for use in Control_config with an associated name
*/
class CC_preset {
public:
public:
SCP_vector<CCB> bindings;
SCP_string name;
Preset_t type = Preset_t::hardcode;
private:
// No default value: the type is always set explicitly by the constructor
Preset_t type;
public:
CC_preset() = default;
CC_preset(const CC_preset& A) = default;
public:
// No default constructor: every preset must be created with an explicit type
CC_preset(SCP_string preset_name, Preset_t preset_type) : name(std::move(preset_name)), type(preset_type) {}
CC_preset(const CC_preset&) = default;
// Preserve target's preset type during copy assignment
CC_preset& operator=(const CC_preset& other);
Preset_t get_type() const
{
return type;
}
bool is_duplicate_of(const CC_preset& other) const;
CC_preset& operator=(const CC_preset&);
/*!
* Checks if the given preset is a duplicate of this one
*/
bool is_duplicate_of(CC_preset&);
};
/*!
+19 -15
View File
@@ -292,8 +292,10 @@ void control_config_common_init_bindings() {
// init default preset
Control_config_presets.clear();
CC_preset preset("default", Preset_t::hardcode);
CC_preset preset;
preset.bindings.reserve(Control_config.size());
preset.name = "default";
preset.type = Preset_t::hardcode;
for (auto &item : Control_config) {
preset.bindings.push_back(CCB(item));
@@ -1731,13 +1733,14 @@ size_t read_bind_1(CC_preset &preset) {
*/
void control_config_common_read_section(int s, bool first_override) {
Assertion((s == 0) || (s == 1), "Expected value of s to be either 0 or 1, found %i instead.", s);
CC_preset new_preset("", Preset_t::tbl);
CC_preset new_preset;
// Set references to the default preset and bindings
auto& default_preset = Control_config_presets[0];
auto& default_bindings = default_preset.bindings;
new_preset.bindings.clear();
new_preset.type = Preset_t::tbl;
if (s == 0) {
// #ControlConfigOverride
@@ -2999,22 +3002,23 @@ CCI_builder& CCI_builder::operator()(IoActionId action_id, short primary, short
return *this;
}
CC_preset& CC_preset::operator=(const CC_preset& other)
{
if (this != &other) {
bindings = other.bindings;
name = other.name;
// 'type' is intentionally preserved to maintain instance identity
}
return *this;
}
CC_preset& CC_preset::operator=(const CC_preset& A) {
name = A.name;
type = A.type;
bool CC_preset::is_duplicate_of(const CC_preset& other) const
{
for (size_t i = 0; i < other.bindings.size(); ++i) {
if (bindings[i] != other.bindings[i]) {
std::copy(A.bindings.begin(), A.bindings.end(), bindings.begin());
return *this;
};
bool CC_preset::is_duplicate_of(CC_preset& A) {
for (size_t i = 0; i < A.bindings.size(); ++i) {
if (bindings[i] != A.bindings[i]) {
// Found a binding that's different. Thus, this preset is not a duplicate
return false;
}
}
// Else, did not find any differences in the bindings. Thus, this preset is a duplicate
return true;
}
+5 -3
View File
@@ -74,7 +74,9 @@ void load_preset_files(SCP_string clone) {
// Start reading in data
CC_preset preset(file, Preset_t::pst);
CC_preset preset;
preset.name = file;
preset.type = Preset_t::pst;
preset.bindings.resize(Control_config.size());
size_t size;
@@ -132,7 +134,7 @@ void load_preset_files(SCP_string clone) {
if ((clone == preset.name) || (it == Control_config_presets.end())) {
Control_config_presets.push_back(preset);
} else if ((it->name != preset.name) || ((it->get_type() != Preset_t::pst))) {
} else if ((it->name != preset.name) || (it->type != Preset_t::pst)) {
if (gameseq_get_state() == GS_STATE_CONTROL_CONFIG) {
popup(PF_TITLE_WHITE | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, "Preset '%s' is a duplicate of an existing preset, ignoring", preset.name.c_str());
} else {
@@ -171,7 +173,7 @@ bool delete_preset_file(CC_preset preset) {
cf_delete(filename.c_str(), CF_TYPE_PLAYER_BINDS, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
// Reload the presets from file.
Control_config_presets.erase(Control_config_presets.begin() + 1, Control_config_presets.end());
Control_config_presets.resize(1);
load_preset_files();
return true;
+4 -6
View File
@@ -1,16 +1,12 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2DArray;
#endif
#include "gamma.sdr"
layout(location=0) out vec4 fragOut0;
#ifdef VULKAN
layout (location = 0) in vec4 fragTexCoord;
layout (location = 1) in vec4 fragColor;
layout (location = 0) out vec4 fragOut0;
layout (set = 1, binding = 1) uniform sampler2DArray baseMap;
layout (set = 2, binding = 0, std140) uniform genericData {
@@ -21,6 +17,8 @@ layout (set = 2, binding = 0, std140) uniform genericData {
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
layout (std140) uniform genericData {
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
#endif
#ifdef VULKAN
layout (location = 0) in vec4 vertPosition;
layout (location = 1) in vec4 vertColor;
+2 -7
View File
@@ -1,16 +1,11 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
layout(location=0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D bloomed;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D bloomed;
#endif
+2 -8
View File
@@ -1,15 +1,9 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
#else
out vec4 fragOut0;
in vec4 fragTexCoord;
uniform sampler2D tex;
#endif
+2 -8
View File
@@ -1,18 +1,12 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
#endif
const float Luminance = 0.08;
const float fMiddleGray = 0.2;
const float fWhiteCutoff = 0.4;
+2 -8
View File
@@ -1,16 +1,10 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
precision highp sampler2DArray;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
#ifdef COPY_ARRAY
uniform sampler2DArray tex;
#else
+4 -15
View File
@@ -1,9 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp sampler2DArray;
#endif
// NOTE: The technique and some of this code is based on this tutorial:
// http://martindevans.me/game-development/2015/02/27/Drawing-Stuff-On-Other-Stuff-With-Deferred-Screenspace-Decals/
@@ -35,14 +29,9 @@ layout (set = 1, binding = 1) uniform sampler2DArray decalTextures;
layout (set = 1, binding = 4) uniform sampler2D gDepthBuffer;
layout (set = 1, binding = 6) uniform sampler2D gNormalBuffer;
#else
layout (location=0) out vec4 fragOut0; // Diffuse buffer
#ifndef GL_ES
layout (location=1) out vec4 fragOut1; // Normal buffer
layout (location=2) out vec4 fragOut2; // Emissive buffer
#else
layout (location=2) out vec4 fragOut1; // Normal buffer -> COLOR_ATTACHMENT2
layout (location=4) out vec4 fragOut2; // Emissive buffer -> COLOR_ATTACHMENT4
#endif
out vec4 fragOut0; // Diffuse buffer
out vec4 fragOut1; // Normal buffer
out vec4 fragOut2; // Emissive buffer
flat in mat4 invModelMatrix;
flat in vec3 decalDirection;
@@ -135,7 +124,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
}
// Make a smooth alpha transition leading up to an edge
alpha = alpha * (1.0 - smoothstep(angle_fade_start, normal_angle_cutoff, angle));
alpha = alpha * (1 - smoothstep(angle_fade_start, normal_angle_cutoff, angle));
return normal;
}
-4
View File
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
#ifdef VULKAN
// Binding 0: box vertex positions
@@ -1,10 +1,3 @@
#ifdef GL_ES
#extension GL_EXT_clip_cull_distance : enable
precision highp float;
precision highp int;
precision highp sampler2DArray;
#endif
#ifdef VULKAN
layout(set = 2, binding = 0, std140)
#else
@@ -27,28 +20,22 @@ uniform genericData {
uint clipEnabled;
};
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
layout(location = 0) in vec4 fragTexCoord;
layout(location = 1) in vec4 fragColor;
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
layout(location = 2) in float vClipDist;
#endif
layout(location = 0) out vec4 fragOut0;
#else
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
in float vClipDist;
#endif
uniform sampler2DArray baseMap;
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
#endif
@@ -56,11 +43,6 @@ in vec4 fragColor;
void main()
{
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
if (clipEnabled != 0u && vClipDist < 0.0) {
discard;
}
#endif
vec4 baseColor = texture(baseMap, vec3(fragTexCoord.xy, float(baseMapIndex)));
if(alphaThreshold > baseColor.a) discard;
baseColor.rgb = (srgb == 1) ? srgb_to_linear(baseColor.rgb) : baseColor.rgb;
@@ -1,9 +1,3 @@
#ifdef GL_ES
#extension GL_EXT_clip_cull_distance : enable
precision highp float;
precision highp int;
#endif
#ifdef VULKAN
layout(set = 2, binding = 0, std140)
#else
@@ -44,15 +38,10 @@ layout(location = 2) in vec4 vertTexCoord;
layout(location = 0) out vec4 fragTexCoord;
layout(location = 1) out vec4 fragColor;
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
layout(location = 2) out float vClipDist;
#endif
#else
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
out float vClipDist;
#endif
out float gl_ClipDistance[1];
out vec4 fragTexCoord;
in vec4 vertTexCoord;
@@ -69,16 +58,13 @@ void main()
gl_Position = projMatrix * modelViewMatrix * vertPosition;
if (clipEnabled != 0u) {
#ifndef SDR_FLAG_SW_CLIP_FALLBACK
gl_ClipDistance[0] = dot(clipEquation, modelMatrix * vertPosition);
#else
vClipDist = dot(clipEquation, modelMatrix * vertPosition);
#endif
} else {
#ifndef SDR_FLAG_SW_CLIP_FALLBACK
#ifdef VULKAN
// Vulkan has no glEnable(GL_CLIP_DISTANCE0) equivalent — clip distances are
// always evaluated when declared in the shader. Must write a positive value
// when clipping is disabled to prevent undefined-value vertex culling.
gl_ClipDistance[0] = 1.0;
#else
vClipDist = 1.0;
#endif
#endif
}
}
@@ -1,14 +1,9 @@
#ifdef GL_ES
precision highp float;
#endif
layout (location=0) out vec4 fragOut0;
layout (location=1) out vec4 fragOut1;
layout (location=2) out vec4 fragOut2;
layout (location=3) out vec4 fragOut3;
layout (location=4) out vec4 fragOut4;
layout (location=5) out vec4 fragOut5;
out vec4 fragOut0;
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
out vec4 fragOut5;
void main()
{
fragOut0 = vec4(0.0, 0.0, 0.0, 1.0); // color
+9 -17
View File
@@ -1,21 +1,13 @@
//? #version 150
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp samplerCube;
precision highp sampler2DArrayShadow;
#endif
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#include "shadows.sdr" //! #include "shadows.sdr"
#include "z-compress.sdr" //! #include "z-compress.sdr"
#ifndef GL_ES
#ifdef VULKAN
layout(location = 0) out vec4 fragOut0;
#else
layout(location = 5) out vec4 fragOut0; //COLOR_ATTACHMENTn is on location n in ES, here it uses COLOR_ATTACHMENT5
out vec4 fragOut0;
#endif
#ifdef VULKAN
@@ -153,7 +145,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
dist = length(lightDirOut);
lightDist = dist;
// Energy conservation term
float alpha_adjust = clamp(alpha + (sourceRadius/(2.0*dist)), 0.0, 1.0);
float alpha_adjust = clamp(alpha + (sourceRadius/(2*dist)), 0.0, 1.0);
area_normalisation = alpha/alpha_adjust;
area_normalisation *= area_normalisation;
//end chunk
@@ -196,7 +188,7 @@ void GetLightInfo(vec3 position, in float alpha, in vec3 reflectDir, out vec3 li
float dist = length(lightDirOut);
lightDist = dist;
// Energy conservation term
float alpha_adjust = min(alpha + (sourceRadius/(2.0*dist)), 1.0);
float alpha_adjust = min(alpha + (sourceRadius/(2*dist)), 1.0);
area_normalisation = alpha/alpha_adjust;
// don't need to square as it's a line rather than a sphere.
//end chunk
@@ -243,11 +235,11 @@ void ComputeEnvLight(float alpha, float ao, vec3 light_dir, vec3 eyeDir, vec3 no
// so let s = (2/alpha^2 - 2)
// 1/2 log(s + 1) = 1/2 log(2/alpha^2 -1)
const float ENV_REZ = 512.0; // Ideally this would be #define'd and shader recompiled with envmap rez changes
const float REZ_BIAS = log2(ENV_REZ * sqrt(3.0));
const float ENV_REZ = 512; // Ideally this would be #define'd and shader recompiled with envmap rez changes
const float REZ_BIAS = log2(ENV_REZ * sqrt(3));
float alphaSqr = alpha * alpha;
float rough_bias = 0.5 * log2(2.0/alphaSqr - 1.0);
float rough_bias = 0.5 * log2(2/alphaSqr - 1);
float mip_bias = REZ_BIAS - rough_bias;
// Sample light, using mip bias to blur it.
@@ -265,7 +257,7 @@ void ComputeEnvLight(float alpha, float ao, vec3 light_dir, vec3 eyeDir, vec3 no
// Pseudo-IBL, so use k_IBL
float k = alpha * alpha/ 2.0f;
float NdotL = max(dot(light_dir, normal),0.0);
float NdotL = max(dot(light_dir, normal),0);
float g1vNL = GeometrySchlickGGX(NdotL, k);
vec3 specEnvLighting = specEnvColour.rgb * fresnel * g1vNL;
@@ -346,6 +338,6 @@ void main()
float NdotL = clamp(dot(normal, lightDir), 0.0, 1.0);
fragmentColor.rgb = computeLighting(specColor.rgb, diffColor, lightDir, normal.xyz, halfVec, eyeDir, roughness, fresnel, NdotL).rgb * diffuseLightColor * attenuation * area_normalisation;
}
fragOut0 = max(fragmentColor, vec4(0.0));
}
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
#include "lighting.sdr"
@@ -1,16 +1,10 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
precision highp sampler2DArray;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec4 fragTexCoord;
layout(location = 1) in vec4 fragColor;
layout(location = 2) in float fragOffset;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
layout(set = 1, binding = 4) uniform sampler2D depthMap;
layout(set = 1, binding = 5) uniform sampler2D frameBuffer;
@@ -20,6 +14,8 @@ in vec4 fragTexCoord;
in vec4 fragColor;
in float fragOffset;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
uniform sampler2D depthMap;
uniform sampler2D distMap;
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
#endif
#ifdef VULKAN
layout(location = 0) in vec4 vertPosition;
layout(location = 1) in vec4 vertColor;
+4 -8
View File
@@ -1,21 +1,15 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp sampler2DArray;
#endif
#include "gamma.sdr"
#include "z-compress.sdr"
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec4 fragTexCoord;
layout(location = 1) in vec4 fragColor;
layout(location = 2) in float fragRadius;
layout(location = 3) in vec4 fragPosition;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
layout(set = 1, binding = 4) uniform sampler2D depthMap;
#else
@@ -24,6 +18,8 @@ in vec4 fragPosition;
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
uniform sampler2D depthMap;
#endif
-4
View File
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
#endif
layout (points) in;
layout (triangle_strip, max_vertices = 4) out;
-3
View File
@@ -1,6 +1,3 @@
#ifdef GL_ES
precision highp float;
#endif
#ifdef VULKAN
layout(location = 0) in vec4 vertPosition;
@@ -1,14 +1,11 @@
#define M_PI 3.1415926535897932384626433832795
#ifdef GL_ES
precision highp float;
precision highp samplerCube;
#endif
uniform samplerCube envmap;
in vec4 fragTexCoord;
layout(location=0) out vec4 fragOut0;
out vec4 fragOut0;
layout (location = 0) out vec4 outColor;
void main() {
const float theta = -fragTexCoord.x * (2.0 * M_PI);
+5 -8
View File
@@ -1,20 +1,17 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
#include "gamma.sdr"
layout(location=0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
layout(set = 1, binding = 4) uniform sampler2D depth_tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
uniform sampler2D depth_tex;
#endif
@@ -43,7 +40,7 @@ void main()
// If the scene is in fog then we change the color we operate on based on the depth of the pixel
float depth_val = texture(depth_tex, fragTexCoord.xy).x;
// Transform depth value from [0, 1] to [-1, 1]
float depth_normalized = 2.0 * depth_val - 1.0;
float depth_normalized = 2 * depth_val - 1;
// Now we compute the depth value in projection space using the clipping plane information
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
@@ -53,7 +50,7 @@ void main()
if (isinf(view_depth)) {
fragOut0.rgb = color_in.rgb;
} else {
float fog_dist = clamp(1.0 - pow(fog_density, view_depth - fog_start) , 0.0, 1.0);
float fog_dist = clamp(1 - pow(fog_density, view_depth - fog_start) , 0.0, 1.0);
vec3 finalFogColor = srgb_to_linear(fog_color);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
+1 -14
View File
@@ -1,12 +1,3 @@
#ifdef GL_ES
#ifdef GL_EXT_gpu_shader5
#extension GL_EXT_gpu_shader5 : enable
#define FXAA_GATHER4_ALPHA 1
#endif
precision highp float;
precision highp sampler2D;
#endif
#define FXAA_EARLY_EXIT 1
#define FXAA_DISCARD 1
#define FXAA_FAST_PIXEL_OFFSET 1 // With OpenGL 3.2 we can always do this
@@ -509,12 +500,8 @@ layout(std140, set = 2, binding = 0) uniform genericData {
#else
uniform sampler2D tex0;
in vec2 v_rcpFrame;
#ifdef GL_ES
in vec2 v_pos;
#else
noperspective in vec2 v_pos;
#endif
layout(location=0)out vec4 fragOut0;
out vec4 fragOut0;
#endif
void main() {
-7
View File
@@ -1,6 +1,3 @@
#ifdef GL_ES
precision highp float;
#endif
#ifdef VULKAN
layout(location = 0) out vec2 fragTexCoord;
@@ -13,11 +10,7 @@ void main() {
in vec4 vertPosition;
out vec2 v_rcpFrame;
#ifdef GL_ES
out vec2 v_pos;
#else
noperspective out vec2 v_pos;
#endif
layout (std140) uniform genericData {
float rt_w;
+2 -8
View File
@@ -1,12 +1,6 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
layout(location=0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
// [0]=real color (passed through as-is), [1]=luma detection proxy (see
// getAADetectionView; may be the same view as [0] when not HDR)
layout(set = 1, binding = 1) uniform sampler2D fxaaTex[2];
@@ -14,9 +8,9 @@ layout(set = 1, binding = 1) uniform sampler2D fxaaTex[2];
#define lumaTex fxaaTex[1]
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
#endif
void main() {
vec4 color = texture(tex, fragTexCoord.xy);
#ifdef VULKAN
@@ -1,17 +1,12 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
#include "gamma.sdr"
layout(location=0)out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
#endif
-3
View File
@@ -1,6 +1,3 @@
#ifdef GL_ES
precision highp float;
#endif
const float SRGB_GAMMA = 2.2;
const float SRGB_GAMMA_INVERSE = 1.0 / SRGB_GAMMA;
+6 -12
View File
@@ -1,21 +1,15 @@
//!#version 150
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp samplerCube;
#endif
#include "gamma.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#define PI 3.1415926535897932384626433832795
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform samplerCube envmap;
#else
uniform samplerCube envmap;
in vec4 fragTexCoord;
out vec4 fragOut0;
#endif
#ifdef VULKAN
@@ -160,8 +154,8 @@ vec3( 0.7305, 0.6698, 0.1333)
);
void main() {
float xpos = 2.0 * gl_FragCoord.x/16.0 - 1.0; // remap to (-1, 1)
float ypos = 2.0 * gl_FragCoord.y/16.0 - 1.0;
float xpos = 2 * gl_FragCoord.x/16 - 1; // remap to (-1, 1)
float ypos = 2 * gl_FragCoord.y/16 - 1;
vec3 fragDir;
vec4 fragCol = vec4(0.0);
@@ -197,5 +191,5 @@ void main() {
vec3 sampDir = points[i] + (aPdotD - PdotD) * fragDir;
fragCol += aPdotD * vec4(srgb_to_linear(texture(envmap, sampDir)).rgb, 1.0);
}
fragOut0 = linear_to_srgb(PI * fragCol * (1.0/128.0));
fragOut0 = linear_to_srgb(PI * fragCol * (1.0/128));
}
+2 -2
View File
@@ -57,7 +57,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
vec3 specular = distribution * fresnel * geometry / (4.0*dotNV*dotNL + 0.0001);
vec3 specular = distribution * fresnel * geometry / (4*dotNV*dotNL + 0.0001);
// Diffuse term - Lambertian, kD represents energy lost to specular reflection.
vec3 kD = vec3(1.0)-fresnel;
@@ -70,7 +70,7 @@ vec3 ComputeGGX(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 ha
vec3 computeLighting(vec3 specColor, vec3 diffColor, vec3 light, vec3 normal, vec3 halfVec, vec3 view, float roughness, float fresnelFactor, float dotNL)
{
#ifdef FLAG_LIGHT_MODEL_BLINN_PHONG
return SpecularBlinnPhong(specColor, light, normal, halfVec, 32.0, fresnelFactor, dotNL);
return SpecularBlinnPhong(specColor, light, normal, halfVec, 32, fresnelFactor, dotNL);
#else
return ComputeGGX(specColor, diffColor, light, normal, halfVec, view, roughness, fresnelFactor, dotNL);
#endif
+3 -8
View File
@@ -1,14 +1,7 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D textures[16];
#define scene textures[0]
@@ -16,6 +9,8 @@ layout(set = 1, binding = 1) uniform sampler2D textures[16];
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D scene;
uniform sampler2D cockpit;
#endif
+14 -31
View File
@@ -1,13 +1,4 @@
//? #version 150
#ifdef GL_ES
#extension GL_EXT_clip_cull_distance: enable
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp sampler2DArray;
precision highp sampler2DArrayShadow;
#endif
#include "shadows.sdr" //! #include "shadows.sdr"
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
@@ -121,13 +112,6 @@ uniform shadowCascadeParams {
vec4 smoothness_factors[(NUM_SHADOW_CASCADES + 4 - 1) / 4];
};
layout(location = 0) out vec4 fragOut0;
layout(location = 1) out vec4 fragOut1;
layout(location = 2) out vec4 fragOut2;
layout(location = 3) out vec4 fragOut3;
layout(location = 4) out vec4 fragOut4;
#ifdef VULKAN
layout(set = 1, binding = 1) uniform sampler2DArray materialTextures[16];
#define sBasemap materialTextures[0]
@@ -155,12 +139,13 @@ layout(location = 0) in VertexOutput {
vec4 shadowUV[NUM_SHADOW_CASCADES];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertIn;
layout(location = 0) out vec4 fragOut0;
layout(location = 1) out vec4 fragOut1;
layout(location = 2) out vec4 fragOut2;
layout(location = 3) out vec4 fragOut3;
layout(location = 4) out vec4 fragOut4;
#else
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
uniform sampler2DArray sBasemap;
@@ -200,10 +185,13 @@ in VertexOutput {
vec4 shadowUV[NUM_SHADOW_CASCADES];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertIn;
out vec4 fragOut0;
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
#endif
vec3 FresnelLazarovEnv(vec3 specColor, vec3 view, vec3 normal, float gloss)
@@ -295,10 +283,6 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
void main()
{
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
if (vertIn.vClipDist < 0.0) discard;
#endif
vec3 eyeDir = vec3(normalize(-vertIn.position).xyz);
vec2 texCoord = vertIn.texCoord.xy;
@@ -480,7 +464,7 @@ void main()
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
// color.
float fogDensityFinal = clamp(1.0 - pow(fogDensity, vertIn.fogDist) , 0.0, 1.0);
float fogDensityFinal = clamp(1 - pow(fogDensity, vertIn.fogDist) , 0.0, 1.0);
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, fogDensityFinal);
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
specColor.rgb *= fogDensityFinal;
@@ -525,12 +509,11 @@ void main()
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
glossData = 0.0f;
glossData = 0;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
// If there is no lighting then we copy the color data so far into the emissive.
emissiveColor.rgb += baseColor.rgb;
aoFactors.x = 0.0f;
aoFactors.x = 0;
// and leave nothing for the light pass to add on top of it
baseColor.rgb = vec3(0.0);
specColor = vec4(0.0);
+1 -26
View File
@@ -1,11 +1,4 @@
#ifdef GL_ES
#extension GL_EXT_gpu_shader5: enable
#extension GL_EXT_clip_cull_distance: enable
precision highp float;
precision highp int;
#else
#extension GL_ARB_gpu_shader5: enable
#endif
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
@@ -107,9 +100,6 @@ in VertexOutput {
vec4 shadowUV[NUM_SHADOW_CASCADES];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertIn[];
out VertexOutput {
@@ -127,10 +117,6 @@ out VertexOutput {
vec4 shadowUV[NUM_SHADOW_CASCADES];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertOut;
#ifdef MODEL_SDR_FLAG_THICK_OUTLINES
@@ -180,19 +166,8 @@ out VertexOutput {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
if (use_clip_plane != 0) {
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
vertOut.vClipDist = vertIn[vert].vClipDist;
#else
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
} else {
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
vertOut.vClipDist = 1.0;
#else
gl_ClipDistance[0] = 1.0;
#endif
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
}
EmitVertex();
}
+6 -32
View File
@@ -1,18 +1,8 @@
#ifndef VULKAN
//? #version 150
#ifdef GL_ES
#extension GL_EXT_gpu_shader5: enable
#extension GL_EXT_clip_cull_distance: enable
precision highp float;
precision highp int;
precision highp samplerBuffer;
precision highp sampler2DArrayShadow;
#else
#extension GL_ARB_gpu_shader5: enable
#endif
#endif
#include "shadows.sdr"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
@@ -155,10 +145,6 @@ layout(location = 0) out VertexOutput {
vec4 shadowUV[NUM_SHADOW_CASCADES];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertOut;
#else
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
@@ -180,10 +166,6 @@ out VertexOutput {
vec4 shadowUV[NUM_SHADOW_CASCADES];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertOut;
#define TEXELS_PER_MATRIX 4
@@ -265,20 +247,12 @@ void main()
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
#ifndef SDR_FLAG_SW_CLIP_FALLBACK
if (use_clip_plane != 0) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#else
if (use_clip_plane != 0) {
vertOut.vClipDist = dot(clip_equation, modelMatrix * orient * vertex);
} else {
vertOut.vClipDist = 1.0;
}
#endif
// Clip plane
if(use_clip_plane != 0) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
vertOut.position = position;
vertOut.normal = normal;
+12 -13
View File
@@ -1,20 +1,14 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2DMS;
#endif
#include "z-compress.sdr"
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(location = 1) out vec4 fragOut1;
layout(location = 2) out vec4 fragOut2;
layout(location = 3) out vec4 fragOut3;
layout(location = 4) out vec4 fragOut4;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(set = 1, binding = 1) uniform sampler2DMS msaaTex[6];
#define texColor msaaTex[0]
#define texPos msaaTex[1]
@@ -29,7 +23,12 @@ layout(std140, set = 2, binding = 0) uniform genericData {
};
#else
in vec4 fragTexCoord;
layout(location=5)out vec4 fragOut5;
out vec4 fragOut0;
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
out vec4 fragOut4;
out vec4 fragOut5;
uniform sampler2DMS texColor;
uniform sampler2DMS texPos;
@@ -177,7 +176,7 @@ float getMedianDist(ivec2 texel) {
//Fallback, do front first
float getMedianDist(ivec2 texel) {
float minDist = -1000000.0;
float minDist = -1000000;
for(int i = 0; i < samples; i++) {
minDist = max(minDist, uncompress_depth_value(texelFetch(texPos, texel, i).z));
}
@@ -191,7 +190,7 @@ float getMedianDist(ivec2 texel) {
void main()
{
vec2 texSize = vec2(textureSize(texColor));
vec2 texSize = textureSize(texColor);
#ifdef VULKAN
ivec2 texel = ivec2(texSize * fragTexCoord);
#else
@@ -207,7 +206,7 @@ void main()
vec4 normal = vec4(0);
vec4 specular = vec4(0);
vec4 emissive = vec4(0);
float depth = 0.0;
float depth = 0;
for(int i = 0; i < SAMPLE_CNT; i++) {
vec4 localPos = texelFetch(texPos, texel, i);
-5
View File
@@ -1,8 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2DArray;
#endif
#ifdef VULKAN
layout (location = 0) in vec2 ftcoord;
-4
View File
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
#ifdef VULKAN
layout (location = 0) in vec4 vertPosition;
+1 -1
View File
@@ -7,6 +7,6 @@
vec3 unpackNormal(vec2 normal_sample) {
vec3 normal;
normal.xy = normal_sample * 2.0 - 1.0;
normal.z = sqrt(1.0 - normal_sample.x * normal_sample.x - normal_sample.y * normal_sample.y);
normal.z = sqrt(1 - normal_sample.x * normal_sample.x - normal_sample.y * normal_sample.y);
return normal;
}
@@ -1,14 +1,9 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
#endif
#include "gamma.sdr"
in vec4 fragTexCoord;
in vec4 fragColor;
layout(location=0) out vec4 fragOut0;
out vec4 fragOut0;
uniform sampler2D baseMap;
+2 -7
View File
@@ -1,16 +1,11 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
layout(set = 1, binding = 4) uniform sampler2D depth_tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
uniform sampler2D depth_tex;
#endif
+3 -8
View File
@@ -1,17 +1,10 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2DArray;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 1) in vec4 fragColor;
layout(location = 2) in vec2 fragScreenPosition;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2DArray baseMap;
#else
@@ -19,6 +12,8 @@ in vec2 fragTexCoord;
in vec4 fragColor;
in vec2 fragScreenPosition;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
#endif
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
#ifdef VULKAN
layout(location = 0) in vec2 vertPosition;
@@ -1,24 +1,5 @@
//? #version 150
#ifdef GL_ES
#extension GL_EXT_clip_cull_distance: enable
precision highp float;
#endif
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
#ifdef VULKAN
layout(location = 0) in VertexOutput {
float vClipDist;
} vertIn;
#else
in VertexOutput {
float vClipDist;
} vertIn;
#endif
#endif
void main()
{
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
if (vertIn.vClipDist < 0.0) discard;
#endif
}
+4 -25
View File
@@ -1,16 +1,9 @@
//? #version 150
#ifdef GL_ES
#extension GL_EXT_gpu_shader5: enable
#extension GL_EXT_clip_cull_distance: enable
precision highp float;
precision highp int;
#else
#extension GL_ARB_gpu_shader5: enable
#endif
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#if defined(GL_ARB_gpu_shader5) || defined(GL_EXT_gpu_shader5)
#ifdef GL_ARB_gpu_shader5
layout(invocations = NUM_SHADOW_CASCADES) in;
#endif
@@ -31,25 +24,16 @@ layout (std140) uniform shadowCascadeParams {
};
in VertexOutput {
#if !defined(GL_ARB_gpu_shader5) && !defined(GL_EXT_gpu_shader5)
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
float clipModel;
vec3 normal;
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertIn[];
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
out VertexOutput {
float vClipDist;
} vertOut;
#endif
void main(void)
{
#if defined(GL_ARB_gpu_shader5) || defined(GL_EXT_gpu_shader5)
#ifdef GL_ARB_gpu_shader5
if (gl_InvocationID >= cascade_count) return;
int cascade_id = cascade_offset + gl_InvocationID;
#else
@@ -65,12 +49,7 @@ void main(void)
}
gl_Layer = cascade_id;
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
vertOut.vClipDist = vertIn[vert].vClipDist;
#else
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
EmitVertex();
}
+3 -31
View File
@@ -1,16 +1,9 @@
//? #version 150
#ifdef GL_ES
#extension GL_EXT_gpu_shader5: enable
#extension GL_EXT_clip_cull_distance: enable
precision highp float;
precision highp int;
precision highp samplerBuffer;
#else
#extension GL_ARB_gpu_shader5: enable
#ifndef GEOMETRY_FALLBACK
#extension GL_ARB_shader_viewport_layer_array : enable
#endif
#endif
#ifdef VULKAN
layout(location = 0) in vec4 vertPosition;
@@ -73,25 +66,12 @@ uniform samplerBuffer transform_tex;
// supports writing gl_Layer from the vertex shader, see CAPABILITY_FAST_SHADOWS).
#ifdef GEOMETRY_FALLBACK
out VertexOutput {
#if !defined(GL_ARB_gpu_shader5) && !defined(GL_EXT_gpu_shader5)
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
float clipModel;
vec3 normal;
#ifdef SDR_FLAG_SW_CLIP_FALLBACK
float vClipDist;
#endif
} vertOut;
#elif defined(SDR_FLAG_SW_CLIP_FALLBACK)
#ifdef VULKAN
layout(location = 0) out VertexOutput {
float vClipDist;
} vertOut;
#else
out VertexOutput {
float vClipDist;
} vertOut;
#endif
#endif
#define TEXELS_PER_MATRIX 4
@@ -132,7 +112,7 @@ void main()
#ifdef VULKAN
int instanceIndex = gl_InstanceIndex;
#else
#if !defined(GL_ARB_gpu_shader5) && !defined(GL_EXT_gpu_shader5)
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
vertOut.instance = float(gl_InstanceIDARB);
#else
@@ -153,19 +133,11 @@ void main()
gl_Position = position;
}
#ifndef SDR_FLAG_SW_CLIP_FALLBACK
if (use_clip_plane != 0) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#else
if (use_clip_plane != 0) {
vertOut.vClipDist = dot(clip_equation, modelMatrix * orient * vertex);
} else {
vertOut.vClipDist = 1.0;
}
#endif
#ifdef GEOMETRY_FALLBACK
vertOut.normal = normal;
@@ -1,22 +1,21 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2DArray;
#endif
#include "gamma.sdr"
const float EMISSIVE_GAIN = 2.0;
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec4 fragImpactUV;
layout(location = 1) in float fragNormOffset;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2DArray shieldMap;
#else
in vec4 fragImpactUV;
in float fragNormOffset;
out vec4 fragOut0;
uniform sampler2DArray shieldMap;
#endif
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp int;
#endif
#ifdef VULKAN
layout(location = 0) in vec4 vertPosition;
+4 -6
View File
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
#ifdef VULKAN
layout(std140, set = 2, binding = 0) uniform genericData {
@@ -20,13 +16,13 @@ layout (std140) uniform genericData {
#include "SMAA.sdr"
layout(location=0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 1) in vec2 fragPixcoord;
layout(location = 2) in vec4 fragOffset[3];
layout(location = 0) out vec4 fragOut0;
// [0]=edgesTex, [1]=areaTex, [2]=searchTex
layout(set = 1, binding = 1) uniform sampler2D smaaTex[3];
#define edgesTex smaaTex[0]
@@ -37,6 +33,8 @@ in vec2 fragTexCoord;
in vec2 fragPixcoord;
in vec4 fragOffset[3];
out vec4 fragOut0;
uniform sampler2D edgesTex;
uniform sampler2D areaTex;
uniform sampler2D searchTex;
+4 -6
View File
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
#ifdef VULKAN
layout(std140, set = 2, binding = 0) uniform genericData {
@@ -20,17 +16,19 @@ layout (std140) uniform genericData {
#include "SMAA.sdr"
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 1) in vec4 fragOffset[3];
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D colorTex;
#else
in vec2 fragTexCoord;
in vec4 fragOffset[3];
out vec4 fragOut0;
uniform sampler2D colorTex;
#endif
@@ -1,7 +1,3 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
#ifdef VULKAN
layout(std140, set = 2, binding = 0) uniform genericData {
@@ -20,12 +16,11 @@ layout (std140) uniform genericData {
#include "SMAA.sdr"
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 1) in vec4 fragOffset;
layout(location = 0) out vec4 fragOut0;
// [0]=colorTex, [1]=blendTex
layout(set = 1, binding = 1) uniform sampler2D smaaTex[2];
@@ -35,6 +30,8 @@ layout(set = 1, binding = 1) uniform sampler2D smaaTex[2];
in vec2 fragTexCoord;
in vec4 fragOffset;
out vec4 fragOut0;
uniform sampler2D colorTex;
uniform sampler2D blendTex;
#endif
@@ -1,15 +1,10 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2D;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
#endif
@@ -1,18 +1,13 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
#endif
#include "gamma.sdr"
layout(location=0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
#endif
+2 -7
View File
@@ -1,12 +1,6 @@
#ifdef GL_ES
precision highp float;
precision highp sampler2DArray;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec4 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2DArray textures[16];
#define ytex textures[0]
@@ -14,6 +8,7 @@ layout(set = 1, binding = 1) uniform sampler2DArray textures[16];
#define vtex textures[2]
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2DArray ytex;
uniform sampler2DArray utex;
uniform sampler2DArray vtex;
+13 -28
View File
@@ -1,14 +1,7 @@
#ifdef GL_ES
precision highp float;
precision highp int;
precision highp sampler2D;
precision highp sampler3D;
#endif
layout(location = 0) out vec4 fragOut0;
#ifdef VULKAN
layout(location = 0) in vec2 fragTexCoord;
layout(location = 0) out vec4 fragOut0;
layout(set = 1, binding = 1) uniform sampler2D tex2D[16];
#define composite tex2D[0]
#define emissive tex2D[1]
@@ -17,7 +10,7 @@ layout(set = 1, binding = 5) uniform sampler3D volume_tex;
layout(set = 1, binding = 6) uniform sampler3D noise_volume_tex;
#else
in vec4 fragTexCoord;
out vec4 fragOut0;
layout (binding = 0) uniform sampler2D composite;
layout (binding = 1) uniform sampler2D emissive;
layout (binding = 2) uniform sampler2D depth_tex;
@@ -84,7 +77,7 @@ void main()
#else
vec4 eyeDirection = p_inv * vec4(fragTexCoord.xy * 2.0 - 1.0, -1, 1);
#endif
eyeDirection.w = 0.0;
eyeDirection.w = 0;
vec3 rayDirection = normalize((v_inv * eyeDirection).xyz);
vec4 color_in = texture(composite, fragTexCoord.xy);
@@ -110,14 +103,14 @@ void main()
#endif
//The t at which the ray enters the nebula cube
float maxtMin = max(0.0, max(tMin.x, max(tMin.y, tMin.z)));
float maxtMin = max(0,max(tMin.x, max(tMin.y, tMin.z)));
//The t at which the ray leaves the nebula cube
float mintMax = min(fragDepth, min(tMax.x, min(tMax.y, tMax.z)));
//The cumulative one minus alpha value of the nebula. Corresponds to the multiplier of the current step when additively drawing to a fragment for which the steps closer to the camera are already drawn.
float cumOMAlpha = 1.0;
float cumOMAlpha = 1;
//The cumulative distance already travelled through the nebula.
float cumnebdist = 0.0;
float cumnebdist = 0;
//The color of the current fragment
vec3 cumcolor = vec3(0, 0, 0);
@@ -128,14 +121,6 @@ void main()
vec3 sidestep = 1.0 / vec3(textureSize(volume_tex, 0));
#ifdef GL_ES
// The emissive texture has a complete mip chain generated by the engine.
ivec2 emissiveSize = textureSize(emissive, 0);
float maxEmissiveLod = float(findMSB(max(emissiveSize.x, emissiveSize.y)));
#else
float maxEmissiveLod = float(textureQueryLevels(emissive) - 1);
#endif
for(float stept = maxtMin; stept < mintMax;) {
//Step setup
vec3 position = camera + rayDirection * stept - nebPos;
@@ -174,7 +159,7 @@ void main()
#ifdef NOISE
//Mix the actual nebula color with the noise color depending on the product of the noise channels multiplied with intensity, smooth-clamped from 0 to 1
vec3 stepcolor_neb = mix(nebulaColor, noiseColor,
smoothstep(0.0, 1.0, (textureGrad(noise_volume_tex, position / noiseColorScale1, gradX, gradY).r + textureGrad(noise_volume_tex, position / noiseColorScale2, gradX, gradY).g) / 2.0 * noiseIntensity));
smoothstep(0, 1, (textureGrad(noise_volume_tex, position / noiseColorScale1, gradX, gradY).r + textureGrad(noise_volume_tex, position / noiseColorScale2, gradX, gradY).g) / 2.0 * noiseIntensity));
#else
vec3 stepcolor_neb = nebulaColor;
#endif
@@ -184,19 +169,19 @@ void main()
//From the current position in the volumetric cloud, sample towards the sun to test whether or not the current part of the nebula is bright or not
for(int dlstep = 1; dlstep <= directionalLightSampleSteps; dlstep++){
//TODO Sample these in a cone towards the sun, not just a line. Also add the high-distance sample for concave nebulae
vec3 dlsteppos = (position - globalLightDirection * (float(dlstep) * directionalLightStepSize)) / nebSize + 0.5;
float dlstepalpha = textureGrad(volume_tex, dlsteppos, gradX, gradY).a * step(0.0, dlsteppos.x) * step(dlsteppos.x, 1.0) * step(0.0, dlsteppos.y) * step(dlsteppos.y, 1.0) * step(0.0, dlsteppos.z) * step(dlsteppos.z, 1.0);
vec3 dlsteppos = (position - globalLightDirection * (dlstep * directionalLightStepSize)) / nebSize + 0.5;
float dlstepalpha = textureGrad(volume_tex, dlsteppos, gradX, gradY).a * step(0, dlsteppos.x) * step(dlsteppos.x, 1) * step(0, dlsteppos.y) * step(dlsteppos.y, 1) * step(0, dlsteppos.z) * step(dlsteppos.z, 1);
directionalLightDepth += dlstepalpha * directionalLightStep;
}
stepcolor_diffuse *= beer_powder_norm * (1.0 - exp(-directionalLightDepth * 2.0)) * exp(-directionalLightDepth);
stepcolor_diffuse *= beer_powder_norm * (1 - exp(-directionalLightDepth * 2.0)) * exp(-directionalLightDepth);
//Emissive
cumnebdist += stepcolor_alpha * stepsize_current;
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0.0, maxEmissiveLod)).rgb;
vec3 stepcolor_emissive = clamp(emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((fragDepth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity, 0.0, 1.0);
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
vec3 stepcolor_emissive = clamp(emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((fragDepth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity, 0, 1);
//Step finish
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0.0, 1.0);
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
cumcolor += stepalpha * cumOMAlpha * stepcolor;
}
-17
View File
@@ -28,23 +28,6 @@ protected:
return FALSE;
m_library = SDL_LoadObject(externlib);
#ifdef __ANDROID__
if (m_library == NULL) {
auto android_path = SDL_GetAndroidInternalStoragePath();
if (android_path != nullptr) {
SCP_string android_full_path = android_path;
if (android_full_path.back() != DIR_SEPARATOR_CHAR) {
android_full_path += DIR_SEPARATOR_CHAR;
}
android_full_path += SCP_string("natives") + DIR_SEPARATOR_CHAR + externlib;
#ifndef NDEBUG
mprintf(("Calling SDL_LoadObject with the following path: '%s'\n", android_full_path.c_str()));
#endif
m_library = SDL_LoadObject(android_full_path.c_str());
}
}
#endif
// check full path as a fallback for our own libraries
// NOTE: basePath is assumed to have a trailing slash!
-4
View File
@@ -289,11 +289,7 @@ GraphicsAPI gr_get_configured_render_api()
#endif
#ifndef __ANDROID__
os::ViewportState Gr_configured_window_state = os::ViewportState::Fullscreen;
#else
os::ViewportState Gr_configured_window_state = os::ViewportState::Borderless;
#endif
static bool mode_change_func(os::ViewportState state, bool initial)
{
+3 -4
View File
@@ -32,7 +32,6 @@
#define GL_CLAMP_VERTEX_COLOR 0x891A
#define GL_CLAMP_FRAGMENT_COLOR 0x891B
#define GL_FIXED_ONLY 0x891D
#define GLAD_GL_ARB_shader_viewport_layer_array 0 // Disabled, no gl_layer in vertex shader //0x8DAE
//Enums Redefinitions
#define GL_CLIP_DISTANCE0 GL_CLIP_DISTANCE0_EXT // GL_EXT_clip_cull_distance
@@ -49,7 +48,6 @@
#define GLAD_GL_ARB_texture_storage GL_TRUE // ES 3.2
#define GLAD_GL_ARB_draw_buffers_blend GL_TRUE // ES 3.2 (glBlendFunci and glBlendEquationi)
#define GLAD_GL_ARB_vertex_attrib_binding GL_TRUE // ES 3.1
#define GL_DEPTH_CLAMP GL_DEPTH_CLAMP_EXT
//Functions Redefinitions
#define glBlendFunciARB glBlendFunci // ES 3.2
@@ -236,7 +234,9 @@ inline void glDrawBuffer(GLenum buf)
}
}
// ES uses layout(location = ) directly on shader
// does not exist on ES, ES uses layout(location=) directly on shader
// Notes:
// -This function is not required to run.
#define glBindFragDataLocation(program, colorNumber, name) ((void)0)
// glPolygonMode() is not supported on ES, no wireframe, GL_FILL is default, GL_POINTS, and GL_LINES needs an alternative path
@@ -254,7 +254,6 @@ static inline void glQueryCounter(GLuint id, GLenum target)
#else
(void)id;
#endif
(void)target;
}
// glGetCompressedTexImage not present on GLES and no equivalent
+3 -5
View File
@@ -6,7 +6,7 @@
#include <direct.h>
#endif
#if !defined __APPLE_CC__ && !defined __ANDROID__ && defined SCP_UNIX
#if !defined __APPLE_CC__ && defined SCP_UNIX
#include<glad/glad_glx.h>
//Required because X defines none and always, which is used later
#undef None
@@ -1394,7 +1394,7 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
Error(LOCATION, "Failed to load OpenGL!");
}
#if !defined __APPLE_CC__ && !defined __ANDROID__ && defined SCP_UNIX
#if !defined __APPLE_CC__ && defined SCP_UNIX
if (!gladLoadGLXLoader(GL_context->getLoaderFunction(), nullptr, 0)) {
Error(LOCATION, "Failed to load GLX!");
}
@@ -1453,9 +1453,7 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
"Deferred lightning is enabled in settings but the gpu does not support the minimum of 6 draw buffers. "
"This will result in rendering errors.");
}
mprintf((" Depth Clamp support : %s\n", GLAD_GL_EXT_depth_clamp ? NOX("YES") : NOX("NO")));
mprintf((" HW Cull distance support : %s\n", GLAD_GL_EXT_clip_cull_distance ? NOX("YES") : NOX("NO")));
mprintf((" Precompiled shaders support : %s\n", GLAD_GL_OES_get_program_binary ? NOX("YES") : NOX("NO")));
mprintf((" Immutable buffer storage support : %s\n", GLAD_GL_EXT_buffer_storage ? NOX("YES") : NOX("NO")));
mprintf((" BGRA8888 format support: %s\n", GLAD_GL_EXT_texture_format_BGRA8888 ? NOX("YES") : NOX("NO")));
+1 -1
View File
@@ -72,7 +72,7 @@ bool gr_opengl_openxr_test_capabilities() {
#ifdef WIN32
bool gr_opengl_openxr_create_session() {
auto hdc = static_cast<HDC>(SDL_GetPointerProperty(SDL_GetWindowProperties(os::getSDLMainWindow()),
SDL_PROP_WINDOW_WIN32_HDC_POINTER,
SDL_PROP_WINDOW_WIN32_HWND_POINTER,
nullptr));
XrGraphicsBindingOpenGLWin32KHR graphicsBinding{
-10
View File
@@ -178,20 +178,10 @@ static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool
#ifndef USE_OPENGL_ES
sflags << "#version " << GLSL_version << " core\n";
if (GLSL_version < 330) {
sflags << "#extension GL_ARB_explicit_attrib_location : enable\n";
}
#else
sflags << "#version " << GLSL_version << " es\n";
#endif
sflags << "#define OPENGL\n";
#ifdef USE_OPENGL_ES
if (!GLAD_GL_EXT_clip_cull_distance) {
sflags << "#define SDR_FLAG_SW_CLIP_FALLBACK\n";
}
#endif
sflags << shader_get_shadow_cascade_defines();
sflags << shader_get_rt_shadow_light_limit_define();
-7
View File
@@ -360,13 +360,6 @@ GLboolean opengl_state::ClipDistance(GLint num, bool state)
GLboolean save_state = clipdistance_Status[num];
#ifdef USE_OPENGL_ES
if (!GLAD_GL_EXT_clip_cull_distance) {
clipdistance_Status[num] = state;
return save_state;
}
#endif
if (state != clipdistance_Status[num]) {
if (state) {
glEnable(GL_CLIP_DISTANCE0+num);
-18
View File
@@ -732,13 +732,7 @@ void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light
glClear(GL_DEPTH_BUFFER_BIT);
#ifdef USE_OPENGL_ES
if (GLAD_GL_EXT_depth_clamp) {
glEnable(GL_DEPTH_CLAMP);
}
#else
glEnable(GL_DEPTH_CLAMP);
#endif
Glowpoint_override_save = Glowpoint_override;
Glowpoint_override = true;
@@ -759,13 +753,7 @@ void gr_opengl_shadow_map_end()
{
gr_end_view_matrix();
#ifdef USE_OPENGL_ES
if (GLAD_GL_EXT_depth_clamp) {
glDisable(GL_DEPTH_CLAMP);
}
#else
glDisable(GL_DEPTH_CLAMP);
#endif
gr_zbuffer_set(ZBUFFER_TYPE_FULL);
GL_state.PopFramebufferState();
@@ -1148,12 +1136,6 @@ void opengl_tnl_set_material_nanovg(nanovg_material* material_info) {
void opengl_tnl_set_material_decal(decal_material* material_info) {
opengl_tnl_set_material(material_info, false);
#ifdef USE_OPENGL_ES
// ES decal outputs use G-buffer locations instead of packed draw-buffer indices.
GL_state.SetAlphaBlendModei(2, material_info->get_blend_mode(1));
GL_state.SetAlphaBlendModei(4, material_info->get_blend_mode(2));
#endif
float u_scale, v_scale;
uint32_t array_index;
-13
View File
@@ -162,19 +162,6 @@ static ShaderVariantInfo SHADER_VARIANTS[] = {
{SDR_TYPE_SHADOW_MAP_GEN, true, SDR_FLAG_SHADOW_FALLBACK, "GEOMETRY_FALLBACK", {}, "Use a geometry shader to select the cascade layer instead of writing gl_Layer from the vertex shader"}
};
static_assert(VATTRIB_MODEL_MATRIX + 4 <= 32, "vertex input mask is 32 bits wide");
uint32_t shader_vertex_input_mask(const ShaderTypeInfo& info)
{
uint32_t mask = 0;
for (auto attr : info.attributes) {
// The Vulkan pipeline drops every location the mask omits, so a mat4 needs all four of its bits.
const uint32_t locations = (attr == VATTRIB_MODEL_MATRIX) ? 4u : 1u;
mask |= ((1u << locations) - 1u) << attr;
}
return mask;
}
const ShaderTypeInfo* shader_get_type_info(shader_type type)
{
for (auto & i : SHADER_TYPES) {
-8
View File
@@ -55,14 +55,6 @@ const ShaderTypeInfo* shader_get_type_info(shader_type type);
// Lookup helper: find variant info by (type, flag). Returns nullptr if not found.
const ShaderVariantInfo* shader_get_variant_info(shader_type type, int flag);
/**
* @brief Bitmask of the vertex attribute locations a shader type reads.
*
* One bit per location; VATTRIB_MODEL_MATRIX contributes bits 8-11 because a
* mat4 input occupies four consecutive locations.
*/
uint32_t shader_vertex_input_mask(const ShaderTypeInfo& info);
// Iterate all variants matching type whose flag bit is set in flags.
void shader_for_each_active_variant(shader_type type, unsigned int flags, const std::function<void(const ShaderVariantInfo&)>& fn);
-1
View File
@@ -959,7 +959,6 @@ void vulkan_render_decals(decal_material* material_info,
// Build pipeline config for decal rendering
PipelineConfig config;
config.shaderType = SDR_TYPE_DECAL;
config.shaderFlags = material_info->get_shader_flags();
config.primitiveType = prim_type;
config.depthMode = material_info->get_depth_mode();
config.depthWriteEnabled = false;
+5 -3
View File
@@ -748,7 +748,7 @@ void VulkanDrawManager::renderShadowDraw(gr_buffer_handle ubo_handle, size_t ubo
}
stateTracker->bindPipeline(pipeline, pipelineManager->getPipelineLayout());
stateTracker->setDepthBias(1024.0f, 1.0f); // GL shadow pass: gr_zbias(-1024) = polygon offset factor 1, units 1024
stateTracker->setDepthBias(-1024.0f, 0.0f);
// Bind descriptor sets: shadowMapData (per-draw) and shadowCascadeParams
// (bound separately, per-frame, via shadow_cascade_params_bind) both live in
@@ -1283,7 +1283,6 @@ bool VulkanDrawManager::applyMaterial(material* mat, primitive_type prim_type, v
// Like opengl_tnl_set_material(), every material draw sets the texture addressing (e.g. MR_FORCE_CLAMP skyboxes)
setTextureAddressing(mat->get_texture_addressing());
vulkan_zbias(mat->get_depth_bias());
// Build pipeline configuration from material
PipelineConfig config = buildPipelineConfig(mat, prim_type);
@@ -1484,6 +1483,9 @@ bool VulkanDrawManager::applyMaterial(material* mat, primitive_type prim_type, v
stateTracker->setStencilMode(GR_STENCIL_NONE);
}
// Set depth bias if needed
stateTracker->setDepthBias(static_cast<float>(mat->get_depth_bias()), 0.0f);
return true;
}
@@ -1541,7 +1543,7 @@ void VulkanDrawManager::draw(primitive_type prim_type, int first_vertex, int ver
m_frameStats.totalVertices += vertex_count;
// Flush any dirty dynamic state (viewport, scissor, depth bias, stencil ref)
// before issuing the draw command. applyMaterial sets some of these AFTER bindPipeline,
// before issuing the draw command. applyMaterial sets these AFTER bindPipeline,
// so they may be dirty even when the pipeline didn't change.
stateTracker->applyDynamicState();
+6 -9
View File
@@ -98,7 +98,8 @@ void vulkan_set_default_material_uniforms(material* material_info)
(clip_plane.normal.xyz.y * clip_plane.position.xyz.y) +
(clip_plane.normal.xyz.z * clip_plane.position.xyz.z));
data->modelMatrix = gr_model_matrix_stack.get_transform();
// Model matrix (identity for now, material doesn't provide one)
vm_matrix4_set_identity(&data->modelMatrix);
} else {
data->clipEnabled = 0;
vm_matrix4_set_identity(&data->modelMatrix);
@@ -612,9 +613,6 @@ void vulkan_calculate_irrmap()
}
// Get envmap cubemap view
if (!texManager->ensureCubemapUploaded(ENVMAP)) {
return;
}
auto* envSlot = bm_get_slot(ENVMAP, true);
if (!envSlot || !envSlot->gr_info) {
return;
@@ -640,6 +638,9 @@ void vulkan_calculate_irrmap()
vk::CommandBuffer cmd = stateTracker->getCommandBuffer();
// End the current swap chain render pass
cmd.endRenderPass();
// Create pipeline for irradiance map generation
PipelineConfig config;
config.shaderType = SDR_TYPE_IRRADIANCE_MAP_GEN;
@@ -710,9 +711,6 @@ void vulkan_calculate_irrmap()
vk::Extent2D irrExtent(irrTs->width, irrTs->height);
// End the swap chain pass only after the early returns above, which never resume it
cmd.endRenderPass();
for (size_t face = 0; face < irrTs->cubeFaceFramebuffers.size(); face++) {
vk::Framebuffer fb = irrTs->cubeFaceFramebuffers[face];
if (!fb) {
@@ -763,8 +761,7 @@ void vulkan_calculate_irrmap()
writer.writeSet(materialSet, VulkanDescriptorManager::getSetTemplate(DescriptorSetIndex::Material));
{
std::array<vk::DescriptorImageInfo, VulkanDescriptorManager::MAX_TEXTURE_BINDINGS> texImages;
// irrmap-f.sdr declares this binding as samplerCube, so every element needs a cube view
texImages.fill(descManager->getFallbacks().textureCube);
texImages.fill(descManager->getFallbacks().texture2D);
texImages[0].imageView = envmapView;
writer.setImageArray(MaterialBinding::TextureArray, texImages);
}
-6
View File
@@ -121,12 +121,6 @@ public:
*/
vk::Pipeline getPipeline(const PipelineConfig& config, const vertex_layout& vertexLayout);
/**
* @brief Destroy all cached pipelines; later getPipeline calls build them again
* @note No submitted or recording command buffer may still use them
*/
void forgetAllPipelines() { m_pipelines.clear(); }
/**
* @brief Get the common pipeline layout
*
@@ -272,7 +272,8 @@ vk::DescriptorImageInfo VulkanDistortion::getTextureInfo() const
// Distortion_texture[!Distortion_switch] binding for thrusters).
// After update() toggles the switch, m_switch points to the old read
// source, which is the texture that was just written.
return {m_sampler, m_tex[m_switch].view, vk::ImageLayout::eShaderReadOnlyOptimal};
return {m_ctx->linearSampler, m_tex[m_switch].view,
vk::ImageLayout::eShaderReadOnlyOptimal};
}
} // namespace graphics::vulkan
@@ -531,9 +531,6 @@ void VulkanLDR::executeLightshafts(vk::CommandBuffer cmd)
if (dot > 0.7f) {
sun_x = asinf_safe(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI * 1.5f + 0.5f;
sun_y = asinf_safe(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI * 1.5f * gr_screen.clip_aspect + 0.5f;
// The formula above is OpenGL's, whose texture V grows upward. The Vulkan fullscreen triangle in
// post-v.sdr has V = 0 at the top of the screen, so flip to the space ls-f.sdr's fragTexCoord is in.
sun_y = 1.0f - sun_y;
found = true;
break;
}
@@ -486,7 +486,6 @@ void VulkanDeferredLighting::render(vk::CommandBuffer cmd)
tcache_slot_vulkan* envMapSlot = nullptr;
tcache_slot_vulkan* irrMapSlot = nullptr;
if (envMapAvailable) {
texMgr->ensureCubemapUploaded(ENVMAP);
envMapSlot = texMgr->getTextureSlot(ENVMAP);
if (!envMapSlot || !envMapSlot->imageView || !envMapSlot->isCubemap) {
envMapAvailable = false;
+4 -25
View File
@@ -1,7 +1,5 @@
#include "VulkanRaytracing.h"
#include "VulkanDeletionQueue.h"
namespace graphics::vulkan {
namespace {
@@ -224,33 +222,14 @@ uint64_t VulkanRaytracingManager::makeKey(int pm_id, int submodel_num)
void VulkanRaytracingManager::destroyBlasEntry(BlasEntry& entry)
{
// TLASes in frames still in flight hold this BLAS's device address, so defer like ensureTlasCapacity does
if (entry.accelStruct) {
getDeletionQueue()->queueAccelerationStructure(entry.accelStruct.release());
}
entry.accelStruct.reset();
if (entry.buffer) {
getDeletionQueue()->queueBuffer(entry.buffer, entry.allocation);
m_device.destroyBuffer(entry.buffer);
entry.buffer = nullptr;
entry.allocation = VulkanAllocation();
} else if (entry.allocation.isValid()) {
m_memoryManager->freeAllocation(entry.allocation);
}
}
void VulkanRaytracingManager::retireBuiltTlases()
{
// a built TLAS may still point at a retired BLAS, and screens that never rebuild the TLAS would keep binding it
for (auto& frame : m_frameTlas) {
if (frame.tlas) {
getDeletionQueue()->queueAccelerationStructure(frame.tlas.release());
}
if (frame.tlasBuffer) {
getDeletionQueue()->queueBuffer(frame.tlasBuffer, frame.tlasAllocation);
frame.tlasBuffer = nullptr;
frame.tlasAllocation = VulkanAllocation();
}
frame.tlasCapacity = 0;
if (entry.allocation.isValid()) {
m_memoryManager->freeAllocation(entry.allocation);
}
}
+1 -3
View File
@@ -93,9 +93,8 @@ public:
/**
* @brief Purge all cached BLASes for a model and free their GPU resources.
* Called from model_unload()/model_free_all() before the model is destroyed.
* @return true if any BLAS was retired (the shadow TLAS binding must then be refreshed)
*/
bool onModelUnloaded(int pm_id);
void onModelUnloaded(int pm_id);
/**
* @brief Rebuild the top-level acceleration structure for this frame from
@@ -173,7 +172,6 @@ private:
const BlasEntry* getOrBuildBlasEntry(int pm_id, int submodel_num);
void destroyBlasEntry(BlasEntry& entry);
void retireBuiltTlases();
bool createRawBuffer(vk::DeviceSize size,
vk::BufferUsageFlags usage,
+2 -10
View File
@@ -182,7 +182,6 @@ const VulkanRaytracingManager::BlasEntry* VulkanRaytracingManager::getOrBuildBla
// address) -- destroy and fall through to rebuild.
destroyBlasEntry(it->second);
m_blasCache.erase(it);
retireBuiltTlases();
}
BlasEntry entry;
@@ -237,27 +236,20 @@ void VulkanRaytracingManager::onModelLoaded(int pm_id)
}
}
bool VulkanRaytracingManager::onModelUnloaded(int pm_id)
void VulkanRaytracingManager::onModelUnloaded(int pm_id)
{
if (!m_enabled) {
return false;
return;
}
bool retired = false;
for (auto it = m_blasCache.begin(); it != m_blasCache.end();) {
if (static_cast<int>(it->first >> 32) == pm_id) {
destroyBlasEntry(it->second);
it = m_blasCache.erase(it);
retired = true;
} else {
++it;
}
}
if (retired) {
retireBuiltTlases();
}
return retired;
}
} // namespace graphics::vulkan
+4 -3
View File
@@ -10,6 +10,7 @@ VulkanRenderFrame::VulkanRenderFrame(vk::Device device, vk::SwapchainKHR swapCha
constexpr vk::FenceCreateInfo fenceCreateInfo;
m_imageAvailableSemaphore = device.createSemaphoreUnique(semaphoreCreateInfo);
m_renderingFinishedSemaphore = device.createSemaphoreUnique(semaphoreCreateInfo);
m_frameInFlightFence = device.createFenceUnique(fenceCreateInfo);
}
bool VulkanRenderFrame::waitForFinish(uint64_t timeoutNs)
@@ -81,8 +82,7 @@ SwapChainStatus VulkanRenderFrame::acquireSwapchainImage(uint32_t& outImageIndex
}
return SwapChainStatus::eSuccess;
}
SwapChainStatus VulkanRenderFrame::submitAndPresent(const SCP_vector<vk::CommandBuffer>& cmdBuffers,
vk::Semaphore renderingFinished)
SwapChainStatus VulkanRenderFrame::submitAndPresent(const SCP_vector<vk::CommandBuffer>& cmdBuffers)
{
Assertion(!m_inFlight, "Cannot submit a frame for presentation when it is still in flight.");
@@ -99,7 +99,7 @@ SwapChainStatus VulkanRenderFrame::submitAndPresent(const SCP_vector<vk::Command
submitInfo.commandBufferCount = static_cast<uint32_t>(cmdBuffers.size());
submitInfo.pCommandBuffers = cmdBuffers.data();
const std::array<vk::Semaphore, 1> signalSemaphores = {renderingFinished};
const std::array<vk::Semaphore, 1> signalSemaphores = {m_renderingFinishedSemaphore.get()};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores.data();
@@ -147,6 +147,7 @@ void VulkanRenderFrame::recreateSyncObjects()
constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo;
m_imageAvailableSemaphore = m_device.createSemaphoreUnique(semaphoreCreateInfo);
m_renderingFinishedSemaphore = m_device.createSemaphoreUnique(semaphoreCreateInfo);
}
} // namespace graphics::vulkan
+2 -1
View File
@@ -30,7 +30,7 @@ class VulkanRenderFrame {
void onFrameFinished(std::function<void()> finishFunc);
SwapChainStatus submitAndPresent(const SCP_vector<vk::CommandBuffer>& cmdBuffers, vk::Semaphore renderingFinished);
SwapChainStatus submitAndPresent(const SCP_vector<vk::CommandBuffer>& cmdBuffers);
void updateSwapChain(vk::SwapchainKHR swapChain);
@@ -50,6 +50,7 @@ class VulkanRenderFrame {
vk::Queue m_presentQueue;
vk::UniqueSemaphore m_imageAvailableSemaphore;
vk::UniqueSemaphore m_renderingFinishedSemaphore;
vk::UniqueFence m_frameInFlightFence;
SCP_vector<std::function<void()>> m_frameFinishedCallbacks;
-9
View File
@@ -430,15 +430,6 @@ void VulkanRenderer::createPresentSyncObjects()
}
m_swapChainImageRenderImage.resize(m_swapChainImages.size(), nullptr);
createRenderingFinishedSemaphores();
}
void VulkanRenderer::createRenderingFinishedSemaphores()
{
constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo;
m_renderingFinishedSemaphores.clear();
for (size_t i = 0; i < m_swapChainImages.size(); ++i) {
m_renderingFinishedSemaphores.push_back(m_device->createSemaphoreUnique(semaphoreCreateInfo));
}
}
bool VulkanRenderer::readbackFramebuffer(ubyte** outPixels, uint32_t* outWidth, uint32_t* outHeight)
-12
View File
@@ -95,12 +95,6 @@ class VulkanRenderer {
*/
void setupFrame();
/**
* @brief Drop every cached pipeline at the start of the next frame; each is rebuilt on its next use
* Called after the shaders are recompiled, since a pipeline keeps the shader code it was built from
*/
void requestPipelineRebuild() { m_pipelinesStale = true; }
/**
* @brief End frame - ends render pass, submits, and presents
* Called at the END of each frame after all draw calls
@@ -457,12 +451,10 @@ class VulkanRenderer {
void createCommandPool(const PhysicalDeviceValues& values);
void createPresentSyncObjects();
void createRenderingFinishedSemaphores();
void acquireNextSwapChainImage();
bool recreateSwapChain();
bool shouldRecreateSwapChain(SwapChainStatus status) const;
void createImGuiDescriptorPool();
void initImGui();
@@ -487,7 +479,6 @@ class VulkanRenderer {
bool m_hdrActive = false; // True when an HDR10 (PQ/BT.2020) swap chain was negotiated
bool m_hdrMetadataSupported = false; // VK_EXT_hdr_metadata device extension enabled
vk::Extent2D m_swapChainExtent;
vk::SurfaceTransformFlagBitsKHR m_swapChainPreTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
// The resolution the engine draws at (gr_screen.max_w/max_h), which is not
// always the window size: when Cmdline_window_res is set,
// SDLGraphicsOperations::createViewport sizes the window from that instead,
@@ -500,8 +491,6 @@ class VulkanRenderer {
SCP_vector<vk::UniqueImageView> m_swapChainImageViews;
SCP_vector<vk::UniqueFramebuffer> m_swapChainFramebuffers;
SCP_vector<VulkanRenderFrame*> m_swapChainImageRenderImage;
// per image, not per frame: a frame's fence does not tell us when present has consumed the semaphore
SCP_vector<vk::UniqueSemaphore> m_renderingFinishedSemaphores;
// HDR composition pipeline: the whole frame is rendered into these fp16
// images (via m_renderPass / m_swapChainFramebuffers) instead of directly
@@ -539,7 +528,6 @@ class VulkanRenderer {
vk::CommandBuffer m_currentCommandBuffer;
SCP_vector<vk::CommandBuffer> m_currentCommandBuffers; // For cleanup
bool m_frameInProgress = false;
bool m_pipelinesStale = false;
// Swap chain recreation
bool m_swapChainNeedsRecreation = false;
+3 -12
View File
@@ -81,7 +81,7 @@ void VulkanRenderer::acquireNextSwapChainImage()
MAX_ACQUIRE_ATTEMPTS);
}
if (shouldRecreateSwapChain(status)) {
if (status == SwapChainStatus::eSuboptimal) {
m_swapChainNeedsRecreation = true;
}
@@ -101,14 +101,6 @@ void VulkanRenderer::setupFrame()
return;
}
// before recording: the recompile can run mid-frame, while the frame being recorded still holds old pipelines
if (m_pipelinesStale) {
mprintf(("Vulkan: shaders were recompiled, rebuilding pipelines\n"));
m_device->waitIdle();
m_pipelineManager->forgetAllPipelines();
m_pipelinesStale = false;
}
// Free completed texture upload command buffers
Assertion(m_textureManager, "Vulkan TextureManager not initialized in setupFrame!");
m_textureManager->frameStart();
@@ -226,10 +218,9 @@ void VulkanRenderer::flip()
});
// Submit and present
auto presentStatus = m_frames[m_currentFrame]->submitAndPresent(m_currentCommandBuffers,
m_renderingFinishedSemaphores[m_currentSwapChainImage].get());
auto presentStatus = m_frames[m_currentFrame]->submitAndPresent(m_currentCommandBuffers);
if (shouldRecreateSwapChain(presentStatus)) {
if (presentStatus == SwapChainStatus::eSuboptimal || presentStatus == SwapChainStatus::eOutOfDate) {
m_swapChainNeedsRecreation = true;
}
+11 -65
View File
@@ -326,17 +326,17 @@ vk::Extent2D windowExtent()
return {static_cast<uint32_t>(gr_screen.max_w), static_cast<uint32_t>(gr_screen.max_h)};
}
vk::Extent2D chooseSwapChainExtent(const vk::SurfaceCapabilitiesKHR& capabilities, uint32_t width, uint32_t height)
vk::Extent2D chooseSwapChainExtent(const PhysicalDeviceValues& values, uint32_t width, uint32_t height)
{
if (capabilities.currentExtent.width != UINT32_MAX) {
return capabilities.currentExtent;
if (values.surfaceCapabilities.currentExtent.width != UINT32_MAX) {
return values.surfaceCapabilities.currentExtent;
} else {
VkExtent2D actualExtent = {width, height};
actualExtent.width = std::max(capabilities.minImageExtent.width,
std::min(capabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(capabilities.minImageExtent.height,
std::min(capabilities.maxImageExtent.height, actualExtent.height));
actualExtent.width = std::max(values.surfaceCapabilities.minImageExtent.width,
std::min(values.surfaceCapabilities.maxImageExtent.width, actualExtent.width));
actualExtent.height = std::max(values.surfaceCapabilities.minImageExtent.height,
std::min(values.surfaceCapabilities.maxImageExtent.height, actualExtent.height));
return actualExtent;
}
@@ -459,11 +459,8 @@ bool VulkanRenderer::initialize()
setTextureManager(m_textureManager.get());
// Initialize shader manager
if (m_deviceFeatures.shaderClipDistance != VK_TRUE) {
mprintf(("Vulkan: HW clip distance not supported, using software clip distance fallback\n"));
}
m_shaderManager = std::make_unique<VulkanShaderManager>();
if (!m_shaderManager->init(m_device.get(), m_deviceFeatures.shaderClipDistance == VK_TRUE)) {
if (!m_shaderManager->init(m_device.get())) {
nprintf(("vulkan", "Failed to initialize Vulkan shader manager!\n"));
return false;
}
@@ -1015,7 +1012,6 @@ bool VulkanRenderer::createLogicalDevice(const PhysicalDeviceValues& deviceValue
enabledFeatures.fillModeNonSolid = supportedFeatures.fillModeNonSolid; // wireframe (GR_FILL_MODE_WIRE -> vk::PolygonMode::eLine)
enabledFeatures.shaderClipDistance = supportedFeatures.shaderClipDistance; // gl_ClipDistance[] in main / shadow-map / default-material vertex shaders
enabledFeatures.textureCompressionBC = supportedFeatures.textureCompressionBC; // BC/DXT texture formats (optional; usage gated by isTextureCompressionBCSupported)
enabledFeatures.textureCompressionETC2 = supportedFeatures.textureCompressionETC2; // ETC2/EAC texture formats (optional)
enabledFeatures.depthClamp = supportedFeatures.depthClamp; // clamp depth in the shadow pass (optional; when absent, CAPABILITY_SHADOWS reports false and shadows are disabled)
vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelStructFeatures;
@@ -1113,7 +1109,7 @@ bool VulkanRenderer::createSwapChain(const PhysicalDeviceValues& deviceValues, v
createInfo.minImageCount = imageCount;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = chooseSwapChainExtent(deviceValues.surfaceCapabilities, window.width, window.height);
createInfo.imageExtent = chooseSwapChainExtent(deviceValues, window.width, window.height);
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment
| vk::ImageUsageFlagBits::eTransferSrc
@@ -1128,19 +1124,7 @@ bool VulkanRenderer::createSwapChain(const PhysicalDeviceValues& deviceValues, v
createInfo.imageSharingMode = vk::SharingMode::eExclusive;
}
// preTransform describes the transform already applied to the rendered content.
// FSO does not pre-rotate it, so request identity whenever supported. If this
// differs from currentTransform (e.g. landscape on an Android phone), the
// presentation engine compensates during presentation. Passing currentTransform
// instead would claim that FSO had already performed that rotation.
auto supported = deviceValues.surfaceCapabilities.supportedTransforms;
if (supported & vk::SurfaceTransformFlagBitsKHR::eIdentity) {
createInfo.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
}
else {
createInfo.preTransform = deviceValues.surfaceCapabilities.currentTransform;
}
createInfo.preTransform = deviceValues.surfaceCapabilities.currentTransform;
createInfo.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
createInfo.presentMode = choosePresentMode(deviceValues);
createInfo.clipped = true;
@@ -1161,7 +1145,6 @@ bool VulkanRenderer::createSwapChain(const PhysicalDeviceValues& deviceValues, v
m_hdrActive = (surfaceFormat.colorSpace == vk::ColorSpaceKHR::eHdr10St2084EXT);
Gr_hdr_output_active = m_hdrActive;
m_swapChainExtent = createInfo.imageExtent;
m_swapChainPreTransform = createInfo.preTransform;
// Without -window_res the render resolution simply is the window, so follow
// gr_screen (which gr_screen_resize() has already updated for this
@@ -1223,42 +1206,6 @@ bool VulkanRenderer::createSwapChain(const PhysicalDeviceValues& deviceValues, v
return true;
}
bool VulkanRenderer::shouldRecreateSwapChain(SwapChainStatus status) const
{
// An already requested rebuild also avoids redundant Android surface queries.
if (m_swapChainNeedsRecreation || status == SwapChainStatus::eOutOfDate) {
return true;
}
if (status != SwapChainStatus::eSuboptimal) {
return false;
}
#ifdef __ANDROID__
if (m_swapChainPreTransform == vk::SurfaceTransformFlagBitsKHR::eIdentity) {
vk::SurfaceCapabilitiesKHR capabilities;
try {
capabilities = m_physicalDevice.getSurfaceCapabilitiesKHR(m_vkSurface.get());
} catch (const vk::SystemError&) {
// Let the normal recreation path handle a failed surface query.
return true;
}
if (capabilities.currentTransform != m_swapChainPreTransform &&
(capabilities.supportedTransforms & m_swapChainPreTransform)) {
const auto window = windowExtent();
const auto extent = chooseSwapChainExtent(capabilities, window.width, window.height);
if (extent == m_swapChainExtent) {
// Android can report SUBOPTIMAL on every present while the compositor
// compensates for our identity preTransform. Rebuilding with the same
// extent and preTransform would just repeat that condition next frame.
return false;
}
}
}
#endif
return true;
}
bool VulkanRenderer::recreateSwapChain()
{
nprintf(("vulkan", "Vulkan: Recreating swap chain...\n"));
@@ -1282,7 +1229,7 @@ bool VulkanRenderer::recreateSwapChain()
// Check for 0x0 extent (minimized window) — caller should retry later
const vk::Extent2D window = windowExtent();
auto extent = chooseSwapChainExtent(freshValues.surfaceCapabilities, window.width, window.height);
auto extent = chooseSwapChainExtent(freshValues, window.width, window.height);
if (extent.width == 0 || extent.height == 0) {
nprintf(("vulkan", "Vulkan: Surface extent is 0x0 (minimized), deferring swap chain recreation\n"));
return false;
@@ -1343,7 +1290,6 @@ bool VulkanRenderer::recreateSwapChain()
// Reset swap chain image tracking
m_swapChainImageRenderImage.clear();
m_swapChainImageRenderImage.resize(m_swapChainImages.size(), nullptr);
createRenderingFinishedSemaphores();
m_previousSwapChainImage = UINT32_MAX;
m_swapChainNeedsRecreation = false;
+11 -14
View File
@@ -1,7 +1,5 @@
#include "VulkanShader.h"
#include "VulkanShaderCompiler.h"
#include "VulkanRenderer.h"
#include "gr_vulkan.h"
namespace graphics::vulkan {
@@ -31,13 +29,12 @@ void vulkan_recompile_all_shaders(const std::function<void(size_t, size_t)>& pro
{
auto* shaderManager = getShaderManager();
shaderManager->recompileAllShaders(progressCallback);
getRendererInstance()->requestPipelineRebuild();
}
VulkanShaderManager::VulkanShaderManager() = default;
VulkanShaderManager::~VulkanShaderManager() = default;
bool VulkanShaderManager::init(vk::Device device, bool hwClipDistance)
bool VulkanShaderManager::init(vk::Device device)
{
if (m_initialized) {
return true;
@@ -47,7 +44,7 @@ bool VulkanShaderManager::init(vk::Device device, bool hwClipDistance)
// Initialize runtime shader compiler
m_compiler = std::make_unique<VulkanShaderCompiler>();
if (!m_compiler->init(hwClipDistance)) {
if (!m_compiler->init()) {
nprintf(("vulkan", "VulkanShaderManager: Failed to initialize shader compiler!\n"));
return false;
}
@@ -130,7 +127,10 @@ void VulkanShaderManager::recompileAllShaders(const std::function<void(size_t, s
nprintf(("vulkan", "VulkanShaderManager: Failed to create vertex module: %s\n", e.what()));
}
}
shader.vertexInputMask = shader_vertex_input_mask(*typeInfo);
shader.vertexInputMask = 0;
for (auto attr : typeInfo->attributes) {
shader.vertexInputMask |= (1u << attr);
}
SCP_string fragFile = typeInfo->frag;
auto fragSpirv = m_compiler->compile(fragFile, vk::ShaderStageFlagBits::eFragment, type, flags, requiresRaytracing);
@@ -146,19 +146,13 @@ void VulkanShaderManager::recompileAllShaders(const std::function<void(size_t, s
}
shader.valid = shader.vertexModule && shader.fragmentModule;
// the inactive anti-aliasing family cannot compile under the current mode, so build it again on next use
if (!shader.valid) {
m_shaderMap.erase(shader_key_t(static_cast<int>(type), flags));
m_freeSlots.push_back(static_cast<size_t>(&shader - m_shaders.data()));
}
}
}
// callers expect 0..total-1, like OpenGL; the retail options popup waits for current + 1 == total
++current;
if (progressCallback) {
progressCallback(current, total);
}
++current;
}
nprintf(("vulkan", "VulkanShaderManager: Recompiled %zu shaders\n", total));
@@ -222,7 +216,10 @@ int VulkanShaderManager::loadShader(shader_type type, unsigned int flags)
vertFile.c_str(), e.what()));
}
}
shader.vertexInputMask = shader_vertex_input_mask(*typeInfo);
shader.vertexInputMask = 0;
for (auto attr : typeInfo->attributes) {
shader.vertexInputMask |= (1u << attr);
}
// Compile fragment shader
SCP_string fragFile = typeInfo->frag;
+1 -1
View File
@@ -59,7 +59,7 @@ public:
* @param device Vulkan logical device
* @return true on success
*/
bool init(vk::Device device, bool hwClipDistance);
bool init(vk::Device device);
/**
* @brief Shutdown and release all shader modules
+27 -82
View File
@@ -8,7 +8,6 @@
#include "globalincs/systemvars.h"
#include "graphics/post_processing.h"
#include <chrono>
#include <md5.h>
#include <shaderc/shaderc.h>
@@ -103,9 +102,8 @@ VulkanShadercLibrary::VulkanShadercLibrary()
VulkanShaderCompiler::VulkanShaderCompiler() = default;
VulkanShaderCompiler::~VulkanShaderCompiler() = default;
bool VulkanShaderCompiler::init(bool hwClipDistance)
bool VulkanShaderCompiler::init()
{
m_hwClipDistance = hwClipDistance;
if (m_initialized) {
return true;
}
@@ -150,13 +148,6 @@ SCP_string VulkanShaderCompiler::buildHeader(vk::ShaderStageFlagBits /*stage*/,
// shaderc automatically predefines VULKAN=100 when targeting Vulkan,
// so we do NOT define it here — doing so causes a "Macro redefined" error.
// gl_ClipDistance[] requires the shaderClipDistance device feature. When the
// device supports it, use the hardware clip path, otherwise
// the shaders fall back to the vClipDist varying (software clipping).
if (!m_hwClipDistance) {
header += "#define SDR_FLAG_SW_CLIP_FALLBACK\n";
}
// Blinn-Phong lighting model (matches OpenGL's opengl_shader_get_header)
if (Detail.lighting < 3) {
header += "#define FLAG_LIGHT_MODEL_BLINN_PHONG\n";
@@ -215,28 +206,6 @@ SCP_string VulkanShaderCompiler::computeSourceHash(const SCP_string& header, con
return md5.hexdigest();
}
// rejects a cache file cut short by a crash or full disk: a complete module ends exactly on an OpFunctionEnd
static bool isCompleteSpirv(const SCP_vector<uint32_t>& spirv)
{
constexpr uint32_t SPIRV_MAGIC = 0x07230203;
constexpr size_t HEADER_WORDS = 5;
constexpr uint32_t OP_FUNCTION_END = 56;
if (spirv.size() < HEADER_WORDS || spirv[0] != SPIRV_MAGIC) {
return false;
}
size_t i = HEADER_WORDS;
uint32_t lastOpcode = 0;
while (i < spirv.size()) {
const uint32_t wordCount = spirv[i] >> 16;
if (wordCount == 0) {
return false;
}
lastOpcode = spirv[i] & 0xFFFF;
i += wordCount;
}
return i == spirv.size() && lastOpcode == OP_FUNCTION_END;
}
SCP_vector<uint32_t> VulkanShaderCompiler::compile(const SCP_string& filename,
vk::ShaderStageFlagBits stage,
shader_type sdrType,
@@ -272,13 +241,10 @@ SCP_vector<uint32_t> VulkanShaderCompiler::compile(const SCP_string& filename,
if (fileSize > 0 && (fileSize % 4) == 0) {
SCP_vector<uint32_t> spirv(fileSize / 4);
if (cfread(spirv.data(), 1, fileSize, cacheFile) == fileSize) {
if (isCompleteSpirv(spirv)) {
cfclose(cacheFile);
nprintf(("vulkan", "VulkanShaderCompiler: Cache hit for %s (flags=0x%x)\n",
filename.c_str(), flags));
return spirv;
}
mprintf(("VulkanShaderCompiler: Ignoring incomplete cache file %s\n", cacheFilename.c_str()));
cfclose(cacheFile);
nprintf(("vulkan", "VulkanShaderCompiler: Cache hit for %s (flags=0x%x)\n",
filename.c_str(), flags));
return spirv;
}
}
cfclose(cacheFile);
@@ -350,29 +316,11 @@ SCP_vector<uint32_t> VulkanShaderCompiler::compile(const SCP_string& filename,
nprintf(("vulkan", "VulkanShaderCompiler: Compiled %s -> %zu bytes SPIR-V\n",
filename.c_str(), byteLen));
// each writer renames its own temp file, so a game crash or a second game never leaves a truncated .spv
const SCP_string tmpFilename = "vk_shader-" + hash + "-" +
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) +
".tmp";
const bool complete = isCompleteSpirv(spirv);
cacheFile = complete ? cfopen(tmpFilename.c_str(), "wb", CF_TYPE_CACHE) : nullptr;
if (!complete) {
mprintf(("VulkanShaderCompiler: Not caching %s: compiled module fails the cache check\n",
cacheFilename.c_str()));
} else if (cacheFile != nullptr) {
const bool written =
cfwrite(spirv.data(), static_cast<int>(spirv.size() * sizeof(uint32_t)), 1, cacheFile) == 1;
const bool closed = cfclose(cacheFile) == 0;
bool saved = false;
if (written && closed) {
// rename() on Windows fails if the target exists
cf_delete(cacheFilename.c_str(), CF_TYPE_CACHE);
saved = cf_rename(tmpFilename.c_str(), cacheFilename.c_str(), CF_TYPE_CACHE) == CF_RENAME_SUCCESS;
}
if (!saved) {
cf_delete(tmpFilename.c_str(), CF_TYPE_CACHE);
mprintf(("VulkanShaderCompiler: Could not write cache file %s\n", cacheFilename.c_str()));
}
// Save to disk cache
cacheFile = cfopen(cacheFilename.c_str(), "wb", CF_TYPE_CACHE);
if (cacheFile != nullptr) {
cfwrite(spirv.data(), static_cast<int>(spirv.size() * sizeof(uint32_t)), 1, cacheFile);
cfclose(cacheFile);
}
}
}
@@ -389,29 +337,26 @@ void VulkanShaderCompiler::purgeOldCache()
const SCP_string PREFIX = "vk_shader-";
const auto TIMEOUT = 2.0 * 30.0 * 24.0 * 60.0 * 60.0; // ~2 months in seconds
SCP_vector<SCP_string> cache_files;
SCP_vector<file_list_info> file_info;
cf_get_file_list(cache_files, CF_TYPE_CACHE, "*.spv", CF_SORT_NONE, &file_info,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
Assertion(cache_files.size() == file_info.size(),
"cf_get_file_list returned different sizes for file names and file informations!");
auto now = std::time(nullptr);
for (const char* ext : {".spv", ".tmp"}) {
SCP_vector<SCP_string> cache_files;
SCP_vector<file_list_info> file_info;
const SCP_string filter = SCP_string("*") + ext;
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, &file_info,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
for (size_t i = 0; i < cache_files.size(); ++i) {
auto& name = cache_files[i];
Assertion(cache_files.size() == file_info.size(),
"cf_get_file_list returned different sizes for file names and file informations!");
if (name.compare(0, PREFIX.size(), PREFIX) != 0) {
continue; // Not our cache file
}
for (size_t i = 0; i < cache_files.size(); ++i) {
auto& name = cache_files[i];
if (name.compare(0, PREFIX.size(), PREFIX) != 0) {
continue; // Not our cache file
}
auto diff = std::difftime(now, file_info[i].write_time);
if (diff > TIMEOUT) {
auto full_name = name + ext;
cf_delete(full_name.c_str(), CF_TYPE_CACHE);
}
auto diff = std::difftime(now, file_info[i].write_time);
if (diff > TIMEOUT) {
auto full_name = name + ".spv";
cf_delete(full_name.c_str(), CF_TYPE_CACHE);
}
}
}
+1 -2
View File
@@ -23,7 +23,7 @@ public:
VulkanShaderCompiler();
~VulkanShaderCompiler();
bool init(bool hwClipDistance);
bool init();
void shutdown();
/**
@@ -69,7 +69,6 @@ private:
std::unique_ptr<VulkanShadercLibrary> m_shaderc;
bool m_initialized = false;
bool m_hwClipDistance = false;
};
} // namespace graphics::vulkan
+2 -2
View File
@@ -351,9 +351,9 @@ void vulkan_zbias(int bias)
if (bias) {
drawManager->setDepthBiasEnabled(true);
if (bias < 0) {
stateTracker->setDepthBias(static_cast<float>(-bias), 1.0f);
stateTracker->setDepthBias(1.0f, static_cast<float>(-bias));
} else {
stateTracker->setDepthBias(static_cast<float>(-bias), 0.0f);
stateTracker->setDepthBias(0.0f, static_cast<float>(-bias));
}
} else {
drawManager->setDepthBiasEnabled(false);
+1 -1
View File
@@ -293,7 +293,7 @@ class VulkanStateTracker {
*
* Must be called before every draw command to ensure dirty dynamic state
* (viewport, scissor, depth bias, stencil ref, line width) is flushed.
* applyMaterial() sets the stencil reference AFTER bindPipeline(), so if
* applyMaterial() sets depth bias/stencil AFTER bindPipeline(), so if
* the pipeline didn't change, those changes would be lost without this.
*/
void applyDynamicState();
+14 -115
View File
@@ -8,13 +8,11 @@
#include "gr_vulkan.h"
#include "graphics/util/pixel_swizzle.h"
#include "bmpman/bm_internal.h"
#include "bmpman/bmpman.h"
#include "ddsutils/ddsutils.h"
#include "ddsutils/bcdec.h"
#include "globalincs/systemvars.h"
#include "ktxutils/ktxutils.h"
#include "ktxutils/etcdec.h"
namespace graphics::vulkan {
@@ -822,15 +820,15 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
return false;
}
uint32_t mipLevels = 1;
size_t blockSize = 0;
if (isCompressed) {
blockSize = get_compressed_block_size(baseCompType);
mipLevels = static_cast<uint32_t>(bm_get_num_mipmaps(handle));
mipLevels = std::max<uint32_t>(mipLevels, 1);
}
// uncompressed DDS cubemaps also store every face's mip chain (face0[mips], face1[mips], ...)
auto mipLevels = static_cast<uint32_t>(bm_get_num_mipmaps(handle));
mipLevels = std::max<uint32_t>(mipLevels, 1);
// A cubemap is six array layers; each face has the same layout.
TextureUploadLayout layout;
layout.width = faceW;
@@ -843,19 +841,6 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
size_t perFaceSize = layerByteSize(layout);
size_t totalDataSize = perFaceSize * 6;
// OpenGL builds the chain for one-level cubemaps, and the env map is sampled at a roughness-based mip
uint32_t imageMipLevels = mipLevels;
bool generateMips = false;
if (!isCompressed && mipLevels == 1) {
const auto fmtProps = m_physicalDevice.getFormatProperties(format);
if ((fmtProps.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear) &&
(fmtProps.optimalTilingFeatures & vk::FormatFeatureFlagBits::eBlitSrc) &&
(fmtProps.optimalTilingFeatures & vk::FormatFeatureFlagBits::eBlitDst)) {
imageMipLevels = calculateMipLevels(faceW, faceH);
generateMips = imageMipLevels > 1;
}
}
// Defer destruction of existing resources
if (ts->image) {
auto* deletionQueue = getDeletionQueue();
@@ -867,14 +852,10 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
ts->image = nullptr;
ts->allocation = VulkanAllocation{};
}
ts->isCubemap = false;
// Create cubemap image (6 layers, eCubeCompatible)
vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled;
if (generateMips) {
usage |= vk::ImageUsageFlagBits::eTransferSrc;
}
if (!createImage(faceW, faceH, imageMipLevels, format, vk::ImageTiling::eOptimal,
if (!createImage(faceW, faceH, mipLevels, format, vk::ImageTiling::eOptimal,
usage, MemoryUsage::GpuOnly, ts->image, ts->allocation, 6, true)) {
nprintf(("vulkan", "VulkanTexture: uploadCubemap: failed to create cubemap image\n"));
return false;
@@ -882,7 +863,7 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
// Create cubemap image view (samplerCube)
ts->imageView = createImageView(ts->image, format, vk::ImageAspectFlagBits::eColor,
imageMipLevels, ImageViewType::Cube, 6);
mipLevels, ImageViewType::Cube, 6);
if (!ts->imageView) {
nprintf(("vulkan", "VulkanTexture: uploadCubemap: failed to create cube image view\n"));
m_device.destroyImage(ts->image);
@@ -907,20 +888,15 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
if (!mapped) {
m_memoryManager->freeAllocation(stagingAllocation);
m_device.destroyBuffer(stagingBuffer);
m_device.destroyImageView(ts->imageView);
ts->imageView = nullptr;
m_device.destroyImage(ts->image);
ts->image = nullptr;
m_memoryManager->freeAllocation(ts->allocation);
return false;
}
// Copy data to staging buffer
// DDS cubemap data layout: face0[mip0..mipN], face1[mip0..mipN], ..., face5[mip0..mipN]
if (!isCompressed && bm->bpp == 24) {
// Convert BGR to BGRA for all 6 faces and their mips
// Convert BGR to BGRA for all 6 faces
graphics::util::expand_BGR_to_BGRA(reinterpret_cast<const uint8_t*>(bm->data),
static_cast<uint8_t*>(mapped), (perFaceSize / 4) * 6);
static_cast<uint8_t*>(mapped), static_cast<size_t>(faceW) * faceH * 6);
} else {
memcpy(mapped, reinterpret_cast<const void*>(bm->data), totalDataSize);
}
@@ -937,18 +913,15 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
// Record transitions + copy and submit async
vk::CommandBuffer cmd = beginSingleTimeCommands();
if (generateMips) {
copyRegions.clear();
}
recordUploadCommands(cmd, ts->image, stagingBuffer, format, faceW, faceH,
imageMipLevels, vk::ImageLayout::eUndefined, generateMips, copyRegions, 6);
mipLevels, vk::ImageLayout::eUndefined, false, copyRegions, 6);
submitUploadAsync(cmd, stagingBuffer, stagingAllocation);
// Update slot info
ts->width = faceW;
ts->height = faceH;
ts->format = format;
ts->mipLevels = imageMipLevels;
ts->mipLevels = mipLevels;
ts->bpp = bm->bpp;
ts->arrayLayers = 6;
ts->bitmapHandle = handle;
@@ -959,7 +932,7 @@ bool VulkanTextureManager::uploadCubemap(int handle, bitmap* bm, int compType)
ts->vScale = 1.0f;
nprintf(("vulkan", "VulkanTexture: Cubemap uploaded: %ux%u, %u mips, format=%d\n",
faceW, faceH, imageMipLevels, static_cast<int>(format)));
faceW, faceH, mipLevels, static_cast<int>(format)));
return true;
}
@@ -1133,10 +1106,6 @@ bool VulkanTextureManager::bm_data(int handle, bitmap* bm, int compType)
isCubemapUpload = (compType == DDS_CUBEMAP_DXT1 || compType == DDS_CUBEMAP_DXT3 ||
compType == DDS_CUBEMAP_DXT5);
}
// bm_is_compressed() returns 0 for uncompressed DDS cubemaps; only comp_type identifies them
if (!isCubemapUpload) {
isCubemapUpload = bm_get_entry(handle)->comp_type == BM_TYPE_CUBEMAP_DDS;
}
if (isCubemapUpload) {
return uploadCubemap(handle, bm, compType);
@@ -1888,13 +1857,7 @@ ubyte* VulkanTextureManager::get_bitmap_from_texture(int bitmap_num, int* width_
ts->format == vk::Format::eBc1RgbaUnormBlock ||
ts->format == vk::Format::eBc2UnormBlock ||
ts->format == vk::Format::eBc3UnormBlock ||
ts->format == vk::Format::eBc7UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8SrgbBlock ||
ts->format == vk::Format::eEtc2R8G8B8A1UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8A1SrgbBlock ||
ts->format == vk::Format::eEtc2R8G8B8A8UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8A8SrgbBlock,
ts->format == vk::Format::eBc7UnormBlock,
"get_bitmap_from_texture: unsupported format %d on bitmap %d"
" — may be a render target or dynamic texture",
static_cast<int>(ts->format), bitmap_num);
@@ -1905,13 +1868,7 @@ ubyte* VulkanTextureManager::get_bitmap_from_texture(int bitmap_num, int* width_
const bool isCompressed = (ts->format == vk::Format::eBc1RgbaUnormBlock ||
ts->format == vk::Format::eBc2UnormBlock ||
ts->format == vk::Format::eBc3UnormBlock ||
ts->format == vk::Format::eBc7UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8SrgbBlock ||
ts->format == vk::Format::eEtc2R8G8B8A1UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8A1SrgbBlock ||
ts->format == vk::Format::eEtc2R8G8B8A8UnormBlock ||
ts->format == vk::Format::eEtc2R8G8B8A8SrgbBlock);
ts->format == vk::Format::eBc7UnormBlock);
const bool hasAlpha = bm_has_alpha_channel(bitmap_num);
const int outChannels = hasAlpha ? 4 : 3;
@@ -1928,12 +1885,6 @@ ubyte* VulkanTextureManager::get_bitmap_from_texture(int bitmap_num, int* width_
case vk::Format::eBc2UnormBlock: blockSize = BCDEC_BC2_BLOCK_SIZE; break;
case vk::Format::eBc3UnormBlock: blockSize = BCDEC_BC3_BLOCK_SIZE; break;
case vk::Format::eBc7UnormBlock: blockSize = BCDEC_BC7_BLOCK_SIZE; break;
case vk::Format::eEtc2R8G8B8UnormBlock:
case vk::Format::eEtc2R8G8B8SrgbBlock: blockSize = ETCDEC_ETC_RGB_BLOCK_SIZE; break;
case vk::Format::eEtc2R8G8B8A1UnormBlock:
case vk::Format::eEtc2R8G8B8A1SrgbBlock: blockSize = ETCDEC_ETC_RGB_A1_BLOCK_SIZE; break;
case vk::Format::eEtc2R8G8B8A8UnormBlock:
case vk::Format::eEtc2R8G8B8A8SrgbBlock: blockSize = ETCDEC_EAC_RGBA_BLOCK_SIZE; break;
default: return nullptr;
}
blockW = (w + 3) / 4;
@@ -2087,18 +2038,6 @@ void VulkanTextureManager::decodeReadbackBuffer(const void* mapped, vk::Format f
case vk::Format::eBc7UnormBlock:
bcdec_bc7(srcBlock, blockColBase, static_cast<int>(copyW * 4));
break;
case vk::Format::eEtc2R8G8B8UnormBlock:
case vk::Format::eEtc2R8G8B8SrgbBlock:
etcdec_etc_rgb(srcBlock, blockColBase, static_cast<int>(copyW * 4));
break;
case vk::Format::eEtc2R8G8B8A1UnormBlock:
case vk::Format::eEtc2R8G8B8A1SrgbBlock:
etcdec_etc_rgb_a1(srcBlock, blockColBase, static_cast<int>(copyW * 4));
break;
case vk::Format::eEtc2R8G8B8A8UnormBlock:
case vk::Format::eEtc2R8G8B8A8SrgbBlock:
etcdec_eac_rgba(srcBlock, blockColBase, static_cast<int>(copyW * 4));
break;
default: break;
}
srcBlock += blockSize;
@@ -2235,46 +2174,6 @@ tcache_slot_vulkan* VulkanTextureManager::getTextureSlot(int handle)
return static_cast<tcache_slot_vulkan*>(slot->gr_info);
}
bool VulkanTextureManager::ensureCubemapUploaded(int handle)
{
if (handle < 0) {
return false;
}
auto* ts = getTextureSlot(handle);
if (ts != nullptr && ts->imageView && ts->isCubemap) {
return true;
}
// one warning and no per-frame retry for a map that cannot be used; handles are reused, signatures are not
const uint signature = bm_get_entry(handle)->signature;
if (signature == m_failedCubemapSignature) {
return false;
}
bool uploaded = false;
// the cubemap kind lives in comp_type; type is just BM_TYPE_DDS
const BM_TYPE type = bm_get_entry(handle)->comp_type;
if (type == BM_TYPE_CUBEMAP_DDS || type == BM_TYPE_CUBEMAP_DXT1 || type == BM_TYPE_CUBEMAP_DXT3 ||
type == BM_TYPE_CUBEMAP_DXT5) {
// same lock as OpenGL's opengl_determine_bpp_and_flags for TCACHE_TYPE_CUBEMAP; DXT data stays compressed
const int compType = bm_is_compressed(handle);
const int bpp = bm_has_alpha_channel(handle) ? 32 : 24;
// bm_lock() uploads through bm_data(); upload here only if that did not leave a cube
bitmap* bmp = bm_lock(handle, static_cast<ubyte>(bpp), BMP_TEX_OTHER);
if (bmp != nullptr) {
ts = getTextureSlot(handle);
uploaded = (ts != nullptr && ts->imageView && ts->isCubemap) || uploadCubemap(handle, bmp, compType);
bm_unlock(handle);
}
}
if (!uploaded) {
m_failedCubemapSignature = signature;
Warning(LOCATION, "Environment map '%s' could not be uploaded as a cubemap; reflections are off.",
bm_get_filename(handle));
}
return uploaded;
}
vk::Format VulkanTextureManager::bppToVkFormat(int bpp, bool compressed, int compressionType)
{
if (compressed) {
@@ -2820,7 +2719,7 @@ void VulkanTextureManager::recordUploadCommands(vk::CommandBuffer cmd, vk::Image
region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = arrayLayers;
region.imageSubresource.layerCount = 1;
region.imageOffset = vk::Offset3D(0, 0, 0);
region.imageExtent = vk::Extent3D(width, height, 1);
+3 -11
View File
@@ -194,13 +194,6 @@ public:
*/
tcache_slot_vulkan* getTextureSlot(int handle);
/**
* @brief Upload a cubemap bitmap as a cubemap if it has not been uploaded yet
* @param[in] handle bitmap handle of a DDS cubemap (compressed or not) or a cubemap render target
* @return true if the handle now has a cubemap image view
*/
bool ensureCubemapUploaded(int handle);
/**
* @brief Bitmap handle of the render target currently bound via bm_set_render_target,
* or -1 when rendering to the default framebuffer. Used by gr.screenToBlob so a
@@ -362,9 +355,9 @@ private:
/**
* @brief Decode a get_bitmap_from_texture() readback buffer into data_out
*
* Handles BC- and ETC2-compressed textures (block-decode via bcdec/etcdec)
* and uncompressed textures (per-format channel expand/convert); data_out
* is tightly packed w*h pixels at outChannels (3 or 4) bytes each.
* Handles both the BC-compressed (block-decode via bcdec) and uncompressed
* (per-format channel expand/convert) cases; data_out is tightly packed
* w*h pixels at outChannels (3 or 4) bytes each.
*/
static void decodeReadbackBuffer(const void* mapped, vk::Format format, bool isCompressed,
uint32_t w, uint32_t h, uint32_t blockW, uint32_t blockH,
@@ -389,7 +382,6 @@ private:
vk::Device m_device;
vk::PhysicalDevice m_physicalDevice;
uint m_failedCubemapSignature = 0;
VulkanMemoryManager* m_memoryManager = nullptr;
vk::CommandPool m_commandPool;
vk::Queue m_graphicsQueue;
+4 -19
View File
@@ -11,7 +11,7 @@
#include "ddsutils/ddsutils.h"
#include "ddsutils/bcdec.h"
#include "globalincs/systemvars.h"
#include "ktxutils/ktxutils.h"
namespace graphics::vulkan {
@@ -28,11 +28,11 @@ int vulkan_preload(int bitmap_num, int /*is_aabitmap*/)
}
// Determine lock parameters based on compression type.
// For compressed DDS/KTX textures, lock with the matching DXT/BC7/ETC2
// flags to get raw compressed data with all pre-baked mipmap levels.
// For compressed DDS textures, lock with the matching DXT/BC7 flags to get
// raw compressed data with all pre-baked mipmap levels.
int compType = bm_is_compressed(bitmap_num);
int lockBpp = 32;
uint lockFlags = BMP_TEX_XPARENT;
ubyte lockFlags = BMP_TEX_XPARENT;
switch (compType) {
case DDS_DXT1:
@@ -60,21 +60,6 @@ int vulkan_preload(int bitmap_num, int /*is_aabitmap*/)
lockBpp = 32;
lockFlags = BMP_TEX_CUBEMAP;
break;
case KTX_ETC2_RGB:
case KTX_ETC2_SRGB:
lockBpp = 24;
lockFlags = BMP_TEX_ETC2_RGB8;
break;
case KTX_ETC2_RGBA_EAC:
case KTX_ETC2_SRGBA_EAC:
lockBpp = 32;
lockFlags = BMP_TEX_ETC2_RGBA8;
break;
case KTX_ETC2_RGB_A1:
case KTX_ETC2_SRGB_A1:
lockBpp = 24;
lockFlags = BMP_TEX_ETC2_RGBA1;
break;
default:
// Uncompressed — use 32bpp decompressed
compType = 0;
Loaded 100 of 169 files, more files were not shown because too many files have changed in this diff. Show more