added opengl es option

This commit is contained in:
izzy2lost
2026-03-06 14:09:09 -05:00
parent aa9815909a
commit ddc32eaea4
23 changed files with 1343 additions and 609 deletions
+24 -1
View File
@@ -485,7 +485,6 @@ list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]gtk.*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]sdl2.*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]console-gl\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]console-vc\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]shader\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]vnc.*\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]xemu-snapshots\\.c$")
list(FILTER XEMU_CORE_SOURCES EXCLUDE REGEX "ui[\\\\/]xemu-thumbnail\\.cc$")
@@ -659,6 +658,30 @@ endif()
file(GLOB_RECURSE QAPI_GEN_SOURCES "${QAPI_GEN_DIR}/*.c")
list(APPEND XEMU_CORE_SOURCES ${QAPI_GEN_SOURCES})
# Generate GL shader headers used by ui/shader.c.
set(XEMU_SHADER_GEN_DIR "${CMAKE_BINARY_DIR}/ui/shader")
set(XEMU_SHADER_INPUTS
"${REPO_ROOT}/ui/shader/texture-blit.frag"
"${REPO_ROOT}/ui/shader/texture-blit.vert"
"${REPO_ROOT}/ui/shader/texture-blit-flip.vert"
)
file(MAKE_DIRECTORY "${XEMU_SHADER_GEN_DIR}")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${XEMU_SHADER_INPUTS})
foreach(SHADER_INPUT ${XEMU_SHADER_INPUTS})
get_filename_component(SHADER_NAME "${SHADER_INPUT}" NAME)
string(REPLACE "." "-" SHADER_OUTPUT_BASENAME "${SHADER_NAME}")
set(SHADER_OUTPUT "${XEMU_SHADER_GEN_DIR}/${SHADER_OUTPUT_BASENAME}.h")
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" "${REPO_ROOT}/scripts/shaderinclude.py" "${SHADER_INPUT}"
OUTPUT_FILE "${SHADER_OUTPUT}"
WORKING_DIRECTORY "${REPO_ROOT}"
RESULT_VARIABLE SHADER_GEN_RESULT
)
if(NOT SHADER_GEN_RESULT EQUAL 0)
message(FATAL_ERROR "Shader header generation failed for ${SHADER_INPUT}")
endif()
endforeach()
# Generate block coroutine wrapper sources (block-gen.c).
set(BLOCK_GEN_C "${CMAKE_BINARY_DIR}/block-gen.c")
execute_process(
+29 -15
View File
@@ -577,14 +577,17 @@ cleanup:
}
struct EmulatorSettings {
int surface_scale = 1; // 1, 2, or 3
int frame_rate_limit = 60; // 30 or 60
int system_memory_mib = 64; // 64 or 128
std::string tcg_thread = "multi"; // "single" or "multi"
int surface_scale = 1; // 1, 2, or 3
int frame_rate_limit = 60; // 30 or 60
int system_memory_mib = 64; // 64 or 128
std::string tcg_thread = "multi"; // "single" or "multi"
std::string renderer = "vulkan"; // "vulkan" or "opengl"
std::string filtering = "linear"; // "linear" or "nearest"
bool use_dsp = false;
bool hrtf = true;
bool cache_shaders = true;
bool hard_fpu = true;
bool vsync = false;
bool skip_boot_anim = false;
};
@@ -645,13 +648,13 @@ static bool WriteConfigToml(const std::string& config_path,
general->insert_or_assign("show_welcome", false);
general->insert_or_assign("skip_boot_anim", settings.skip_boot_anim);
display->insert_or_assign("renderer", "vulkan");
if (!display->contains("filtering")) {
display->insert_or_assign("filtering", "nearest");
}
if (!display_window->contains("vsync")) {
display_window->insert_or_assign("vsync", false);
{
const std::string r = (settings.renderer == "opengl") ? "opengl" : "vulkan";
display->insert_or_assign("renderer", r);
}
display->insert_or_assign(
"filtering", settings.filtering == "nearest" ? "nearest" : "linear");
display_window->insert_or_assign("vsync", settings.vsync);
// User-controlled settings (always written so they take effect immediately)
{
int scale = settings.surface_scale;
@@ -678,9 +681,6 @@ static bool WriteConfigToml(const std::string& config_path,
if (!audio->contains("volume_limit")) {
audio->insert_or_assign("volume_limit", 1.0);
}
if (!android->contains("force_cpu_blit")) {
android->insert_or_assign("force_cpu_blit", false);
}
if (!android->contains("tcg_tuning")) {
android->insert_or_assign("tcg_tuning", true);
}
@@ -830,6 +830,19 @@ static SetupFiles SyncSetupFiles() {
emuSettings.tcg_thread = "single";
}
}
{
std::string rendererPref = GetPrefString(env, activity, "setting_renderer");
if (rendererPref == "opengl") {
emuSettings.renderer = "opengl";
}
}
{
std::string filteringPref = GetPrefString(env, activity, "setting_filtering");
if (filteringPref == "nearest") {
emuSettings.filtering = "nearest";
}
}
emuSettings.vsync = GetPrefBool(env, activity, "setting_vsync", false);
out.audio_driver = GetPrefString(env, activity, "setting_audio_driver");
int displayMode = GetPrefInt(env, activity, "setting_display_mode", 0);
@@ -988,12 +1001,13 @@ extern "C" int SDL_main(int argc, char* argv[]) {
} else if (!g_config.sys.files.eeprom_path) {
xemu_settings_set_string(&g_config.sys.files.eeprom_path, "");
}
setenv("XEMU_ANDROID_FORCE_CPU_BLIT", "0", 1);
g_config.general.show_welcome = false;
g_config.perf.cache_shaders = true;
LogInfoInt("Config final show_welcome=%d", g_config.general.show_welcome ? 1 : 0);
LogInfoInt("Config final cache_shaders=%d", g_config.perf.cache_shaders ? 1 : 0);
LogInfoInt("Config final renderer=%d", (int)g_config.display.renderer);
LogInfoFmt("Config final renderer=%s",
(g_config.display.renderer == 0) ? "Vulkan" :
(g_config.display.renderer == 1) ? "OpenGL" : "Null");
LogInfoFmt("Config final bootrom=%s", g_config.sys.files.bootrom_path ? g_config.sys.files.bootrom_path : "(null)");
LogInfoFmt("Config final flashrom=%s", g_config.sys.files.flashrom_path ? g_config.sys.files.flashrom_path : "(null)");
LogInfoFmt("Config final hdd=%s", g_config.sys.files.hdd_path ? g_config.sys.files.hdd_path : "(null)");
@@ -68,7 +68,7 @@ static void xemu_settings_apply_defaults(void)
g_config.input.keyboard_controller_scancode_map.rtrigger = 18;
g_config.display.renderer = CONFIG_DISPLAY_RENDERER_VULKAN;
g_config.display.filtering = CONFIG_DISPLAY_FILTERING_NEAREST;
g_config.display.filtering = CONFIG_DISPLAY_FILTERING_LINEAR;
g_config.display.quality.surface_scale = 1;
g_config.display.window.fullscreen_on_startup = false;
g_config.display.window.fullscreen_exclusive = false;
@@ -209,7 +209,6 @@ bool xemu_settings_load(void)
xemu_settings_apply_defaults();
error_msg.clear();
setenv("XEMU_ANDROID_FORCE_CPU_BLIT", "0", 1);
setenv("XEMU_ANDROID_TCG_TUNING", "1", 1);
setenv("XEMU_ANDROID_TCG_THREAD", "multi", 1);
setenv("XEMU_ANDROID_TCG_TB_SIZE", "128", 1);
@@ -247,13 +246,17 @@ bool xemu_settings_load(void)
g_config.general.skip_boot_anim = *skip_boot_anim;
}
// Display settings - force Vulkan on Android
g_config.display.renderer = CONFIG_DISPLAY_RENDERER_VULKAN;
// Display settings
if (auto renderer = display["renderer"].value<std::string>()) {
CONFIG_DISPLAY_RENDERER parsed;
if (parse_renderer(*renderer, &parsed) && parsed != CONFIG_DISPLAY_RENDERER_VULKAN) {
if (parse_renderer(*renderer, &parsed)) {
g_config.display.renderer = parsed;
__android_log_print(ANDROID_LOG_INFO, "xemu-android",
"Config display.renderer=%s (%d)",
renderer->c_str(), (int)parsed);
} else {
__android_log_print(ANDROID_LOG_WARN, "xemu-android",
"Config display.renderer=%s requested, but Android forces Vulkan",
"Config display.renderer=%s unknown, using default",
renderer->c_str());
}
}
@@ -311,9 +314,6 @@ bool xemu_settings_load(void)
}
// Android-specific settings
if (auto force_cpu_blit = android_cfg["force_cpu_blit"].value<bool>()) {
setenv("XEMU_ANDROID_FORCE_CPU_BLIT", *force_cpu_blit ? "1" : "0", 1);
}
if (auto egl_offscreen = android_cfg["egl_offscreen"].value<bool>()) {
if (!*egl_offscreen) {
setenv("XEMU_ANDROID_EGL_OFFSCREEN", "0", 1);
@@ -79,6 +79,8 @@ class SettingsActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
val toggleGraphicsApi = findViewById<MaterialButtonToggleGroup>(R.id.toggle_graphics_api)
val toggleFiltering = findViewById<MaterialButtonToggleGroup>(R.id.toggle_filtering)
val toggleScale = findViewById<MaterialButtonToggleGroup>(R.id.toggle_resolution_scale)
val btn1x = findViewById<MaterialButton>(R.id.btn_scale_1x)
val btn2x = findViewById<MaterialButton>(R.id.btn_scale_2x)
@@ -93,6 +95,7 @@ class SettingsActivity : AppCompatActivity() {
val switchHrtf = findViewById<MaterialSwitch>(R.id.switch_hrtf)
val switchShaders = findViewById<MaterialSwitch>(R.id.switch_cache_shaders)
val switchFpu = findViewById<MaterialSwitch>(R.id.switch_hard_fpu)
val switchVsync = findViewById<MaterialSwitch>(R.id.switch_vsync)
val switchSkipBootAnim = findViewById<MaterialSwitch>(R.id.switch_skip_boot_anim)
val toggleAudioDriver = findViewById<MaterialButtonToggleGroup>(R.id.toggle_audio_driver)
val btnSave = findViewById<MaterialButton>(R.id.btn_settings_save)
@@ -106,6 +109,20 @@ class SettingsActivity : AppCompatActivity() {
dropdownEepromVideoStandard = findViewById(R.id.dropdown_eeprom_video_standard)
// Load current values
val renderer = prefs.getString("setting_renderer", "vulkan") ?: "vulkan"
if (renderer == "opengl") {
toggleGraphicsApi.check(R.id.btn_renderer_opengl)
} else {
toggleGraphicsApi.check(R.id.btn_renderer_vulkan)
}
val filtering = prefs.getString("setting_filtering", "linear") ?: "linear"
if (filtering == "nearest") {
toggleFiltering.check(R.id.btn_filtering_nearest)
} else {
toggleFiltering.check(R.id.btn_filtering_linear)
}
val scale = prefs.getInt("setting_surface_scale", 1)
when (scale) {
2 -> toggleScale.check(R.id.btn_scale_2x)
@@ -147,6 +164,7 @@ class SettingsActivity : AppCompatActivity() {
switchHrtf.isChecked = prefs.getBoolean("setting_hrtf", true)
switchShaders.isChecked = prefs.getBoolean("setting_cache_shaders", true)
switchFpu.isChecked = prefs.getBoolean("setting_hard_fpu", true)
switchVsync.isChecked = prefs.getBoolean("setting_vsync", false)
switchSkipBootAnim.isChecked =
prefs.getBoolean("setting_skip_boot_anim", false)
@@ -199,6 +217,14 @@ class SettingsActivity : AppCompatActivity() {
R.id.btn_audio_disabled -> "dummy"
else -> "openslES"
}
val selectedRenderer = when (toggleGraphicsApi.checkedButtonId) {
R.id.btn_renderer_opengl -> "opengl"
else -> "vulkan"
}
val selectedFiltering = when (toggleFiltering.checkedButtonId) {
R.id.btn_filtering_nearest -> "nearest"
else -> "linear"
}
val edit = prefs.edit()
.putInt("setting_display_mode", selectedDisplayMode)
@@ -210,8 +236,11 @@ class SettingsActivity : AppCompatActivity() {
.putBoolean("setting_hrtf", switchHrtf.isChecked)
.putBoolean("setting_cache_shaders", switchShaders.isChecked)
.putBoolean("setting_hard_fpu", switchFpu.isChecked)
.putBoolean("setting_vsync", switchVsync.isChecked)
.putBoolean("setting_skip_boot_anim", switchSkipBootAnim.isChecked)
.putString("setting_audio_driver", selectedAudioDriver)
.putString("setting_filtering", selectedFiltering)
.putString("setting_renderer", selectedRenderer)
when {
clearVulkan -> edit
@@ -55,6 +55,82 @@
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
android:textColor="@color/xemu_green" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:text="@string/settings_graphics_api"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="@color/xemu_text_muted" />
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggle_graphics_api"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_renderer_vulkan"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/settings_graphics_api_vulkan" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_renderer_opengl"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/settings_graphics_api_opengl" />
</com.google.android.material.button.MaterialButtonToggleGroup>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:text="@string/settings_filtering"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="@color/xemu_text_muted" />
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggle_filtering"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_filtering_linear"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/settings_filtering_linear" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_filtering_nearest"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/settings_filtering_nearest" />
</com.google.android.material.button.MaterialButtonToggleGroup>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/switch_vsync"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/settings_vsync"
android:textColor="@color/xemu_text_muted" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -80,6 +80,13 @@
<string name="settings_save">Save</string>
<string name="settings_section_display">Display</string>
<string name="settings_graphics_api">Graphics API</string>
<string name="settings_graphics_api_vulkan">Vulkan</string>
<string name="settings_graphics_api_opengl">OpenGL ES</string>
<string name="settings_filtering">Display Filtering</string>
<string name="settings_filtering_linear">Linear</string>
<string name="settings_filtering_nearest">Nearest</string>
<string name="settings_vsync">VSync</string>
<string name="settings_section_vulkan_driver">Custom Vulkan Driver</string>
<string name="settings_vulkan_driver_none">System Default</string>
<string name="settings_vulkan_driver_browse">Browse…</string>
-2
View File
@@ -25,8 +25,6 @@ void nv2a_init(PCIBus *bus, int devfn, MemoryRegion *ram);
void nv2a_context_init(void);
#ifdef __ANDROID__
void nv2a_android_early_context_init(void);
bool nv2a_android_copy_readback(uint8_t **buffer, size_t *buffer_size,
int *width, int *height);
#endif
int nv2a_get_framebuffer_surface(void);
void nv2a_release_framebuffer_surface(void);
+102 -214
View File
@@ -26,180 +26,110 @@
#include "renderer.h"
#include <math.h>
#ifdef __ANDROID__
#include <android/log.h>
#include "qemu/thread.h"
#include <string.h>
#include "system/memory.h"
#endif
#ifdef __ANDROID__
static void check_gl_error_android(const char *context)
static void gl_log_errors(const char *ctx)
{
GLenum err;
int count = 0;
while ((err = glGetError()) != GL_NO_ERROR) {
fprintf(stderr, "GL error 0x%X in %s\n", err, context);
if (++count >= 10) {
break;
}
GLenum gl_err;
while ((gl_err = glGetError()) != GL_NO_ERROR) {
__android_log_print(ANDROID_LOG_WARN, "xemu-android",
"GL error 0x%X at %s", gl_err, ctx);
}
}
#define GL_ASSERT_NO_ERROR(context) check_gl_error_android(context)
#define GL_ASSERT_NO_ERROR(ctx) gl_log_errors(ctx)
#else
#define GL_ASSERT_NO_ERROR(context) assert(glGetError() == GL_NO_ERROR)
#endif
#ifdef __ANDROID__
static QemuMutex g_android_readback_mutex;
static bool g_android_readback_mutex_init = false;
static uint8_t *g_android_readback_buf = NULL;
static size_t g_android_readback_size = 0;
static int g_android_readback_w = 0;
static int g_android_readback_h = 0;
static bool g_android_readback_ready = false;
typedef struct AndroidDisplayGLState {
GLint framebuffer;
GLint program;
GLint vertex_array;
GLint array_buffer;
GLint active_texture;
GLint texture_2d_unit0;
GLint viewport[4];
GLboolean color_mask[4];
GLfloat clear_color[4];
GLboolean scissor_test;
GLboolean blend;
GLboolean stencil_test;
GLboolean cull_face;
GLboolean depth_test;
} AndroidDisplayGLState;
static bool android_force_cpu_blit(void)
static void android_display_capture_gl_state(AndroidDisplayGLState *state)
{
static int cached = -1;
if (cached < 0) {
const char *env = getenv("XEMU_ANDROID_FORCE_CPU_BLIT");
if (!env) {
cached = 1;
} else if (!strcmp(env, "1") || !strcmp(env, "true") ||
!strcmp(env, "TRUE")) {
cached = 1;
} else {
cached = 0;
}
}
return cached == 1;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &state->framebuffer);
glGetIntegerv(GL_CURRENT_PROGRAM, &state->program);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &state->vertex_array);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &state->array_buffer);
glGetIntegerv(GL_ACTIVE_TEXTURE, &state->active_texture);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &state->texture_2d_unit0);
glActiveTexture(state->active_texture);
glGetIntegerv(GL_VIEWPORT, state->viewport);
glGetBooleanv(GL_COLOR_WRITEMASK, state->color_mask);
glGetFloatv(GL_COLOR_CLEAR_VALUE, state->clear_color);
state->scissor_test = glIsEnabled(GL_SCISSOR_TEST);
state->blend = glIsEnabled(GL_BLEND);
state->stencil_test = glIsEnabled(GL_STENCIL_TEST);
state->cull_face = glIsEnabled(GL_CULL_FACE);
state->depth_test = glIsEnabled(GL_DEPTH_TEST);
}
static bool android_readback_is_black(const uint8_t *buf, size_t size,
int width, int height)
static void android_display_restore_gl_state(
const AndroidDisplayGLState *state)
{
if (!buf || size < 4 || width <= 0 || height <= 0) {
return false;
}
size_t tl_off = 0;
size_t mid_off = ((size_t)(height / 2) * (size_t)width +
(size_t)(width / 2)) * 4;
size_t br_off = ((size_t)(height - 1) * (size_t)width +
(size_t)(width - 1)) * 4;
uint32_t tl = 0, mid = 0, br = 0;
if (tl_off + 4 <= size) {
memcpy(&tl, buf + tl_off, sizeof(tl));
}
if (mid_off + 4 <= size) {
memcpy(&mid, buf + mid_off, sizeof(mid));
}
if (br_off + 4 <= size) {
memcpy(&br, buf + br_off, sizeof(br));
}
bool black_tl = (tl == 0x00000000u || tl == 0xff000000u);
bool black_mid = (mid == 0x00000000u || mid == 0xff000000u);
bool black_br = (br == 0x00000000u || br == 0xff000000u);
return black_tl && black_mid && black_br;
}
glBindFramebuffer(GL_FRAMEBUFFER, state->framebuffer);
glUseProgram(state->program);
glBindVertexArray(state->vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, state->array_buffer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, state->texture_2d_unit0);
glActiveTexture(state->active_texture);
glViewport(state->viewport[0], state->viewport[1],
state->viewport[2], state->viewport[3]);
glColorMask(state->color_mask[0], state->color_mask[1],
state->color_mask[2], state->color_mask[3]);
glClearColor(state->clear_color[0], state->clear_color[1],
state->clear_color[2], state->clear_color[3]);
static void android_store_readback(NV2AState *d, SurfaceBinding *surface,
int width, int height)
{
if (width <= 0 || height <= 0) {
return;
if (state->scissor_test) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
if (!g_android_readback_mutex_init) {
qemu_mutex_init(&g_android_readback_mutex);
g_android_readback_mutex_init = true;
if (state->blend) {
glEnable(GL_BLEND);
} else {
glDisable(GL_BLEND);
}
size_t needed = (size_t)width * (size_t)height * 4;
qemu_mutex_lock(&g_android_readback_mutex);
if (needed > g_android_readback_size) {
g_android_readback_buf = g_realloc(g_android_readback_buf, needed);
g_android_readback_size = needed;
if (state->stencil_test) {
glEnable(GL_STENCIL_TEST);
} else {
glDisable(GL_STENCIL_TEST);
}
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
g_android_readback_buf);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
bool display_black = android_readback_is_black(
g_android_readback_buf, g_android_readback_size, width, height);
bool used_surface = false;
if (display_black && d && surface && surface->gl_buffer) {
PGRAPHState *pg = &d->pgraph;
PGRAPHGLState *r = pg->gl_renderer_state;
unsigned int surf_w = surface->width;
unsigned int surf_h = surface->height;
pgraph_apply_scaling_factor(pg, &surf_w, &surf_h);
if (surf_w > 0 && surf_h > 0) {
size_t surf_needed = (size_t)surf_w * (size_t)surf_h * 4;
if (surf_needed > g_android_readback_size) {
g_android_readback_buf = g_realloc(g_android_readback_buf,
surf_needed);
g_android_readback_size = surf_needed;
}
GLint prev_fbo = 0;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, r->disp_rndr.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, surface->gl_buffer, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, surf_w, surf_h, GL_RGBA, GL_UNSIGNED_BYTE,
g_android_readback_buf);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, r->gl_display_buffer, 0);
glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
g_android_readback_w = (int)surf_w;
g_android_readback_h = (int)surf_h;
used_surface = true;
static unsigned int surf_log = 0;
if ((surf_log++ % 120) == 0) {
__android_log_print(ANDROID_LOG_WARN, "xemu-android",
"android readback: display black, using surface vram=0x%x size=%ux%u",
(unsigned)surface->vram_addr,
surf_w, surf_h);
}
}
if (state->cull_face) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
if (!used_surface) {
g_android_readback_w = width;
g_android_readback_h = height;
if (state->depth_test) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
g_android_readback_ready = true;
qemu_mutex_unlock(&g_android_readback_mutex);
}
bool nv2a_android_copy_readback(uint8_t **buffer, size_t *buffer_size,
int *width, int *height)
{
if (!android_force_cpu_blit()) {
return false;
}
if (!g_android_readback_mutex_init || !g_android_readback_ready) {
return false;
}
qemu_mutex_lock(&g_android_readback_mutex);
size_t needed = (size_t)g_android_readback_w * (size_t)g_android_readback_h * 4;
if (!g_android_readback_buf || needed == 0) {
qemu_mutex_unlock(&g_android_readback_mutex);
return false;
}
if (*buffer_size < needed) {
*buffer = g_realloc(*buffer, needed);
*buffer_size = needed;
}
memcpy(*buffer, g_android_readback_buf, needed);
*width = g_android_readback_w;
*height = g_android_readback_h;
qemu_mutex_unlock(&g_android_readback_mutex);
return true;
}
#endif
void pgraph_gl_init_display(NV2AState *d)
{
struct PGRAPHState *pg = &d->pgraph;
@@ -556,16 +486,6 @@ static void render_display(NV2AState *d, SurfaceBinding *surface)
glDrawBuffers(1, DrawBuffers);
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "xemu-android",
"render_display: framebuffer incomplete 0x%X (fmt=%d ifmt=%d type=%d size=%ux%u)",
fb_status,
r->gl_display_buffer_format,
r->gl_display_buffer_internal_format,
r->gl_display_buffer_type,
r->gl_display_buffer_width,
r->gl_display_buffer_height);
#else
fprintf(stderr,
"render_display: framebuffer incomplete 0x%X (fmt=%d ifmt=%d type=%d size=%ux%u)\n",
fb_status,
@@ -574,7 +494,6 @@ static void render_display(NV2AState *d, SurfaceBinding *surface)
r->gl_display_buffer_type,
r->gl_display_buffer_width,
r->gl_display_buffer_height);
#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -582,44 +501,13 @@ static void render_display(NV2AState *d, SurfaceBinding *surface)
}
glBindTexture(GL_TEXTURE_2D, surface->gl_buffer);
#ifdef __ANDROID__
bool clip_enable = false;
float clip_x = 0.0f;
float clip_y = 0.0f;
float clip_w = 0.0f;
float clip_h = 0.0f;
if (android_force_cpu_blit()) {
clip_x = (float)surface->shape.clip_x;
clip_y = (float)surface->shape.clip_y;
clip_w = (float)surface->shape.clip_width;
clip_h = (float)surface->shape.clip_height;
if (clip_w > 0.0f && clip_h > 0.0f) {
clip_enable = true;
static unsigned int clip_log = 0;
if ((clip_log++ % 120) == 0) {
GLint tex_w = 0;
GLint tex_h = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &tex_w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &tex_h);
__android_log_print(ANDROID_LOG_WARN, "xemu-android",
"render_display: clip rect x=%g y=%g w=%g h=%g tex=%dx%d disp=%ux%u",
clip_x, clip_y, clip_w, clip_h,
(int)tex_w, (int)tex_h,
width, height);
}
}
}
#endif
glBindVertexArray(r->disp_rndr.vao);
glBindBuffer(GL_ARRAY_BUFFER, r->disp_rndr.vbo);
glUseProgram(r->disp_rndr.prog);
glProgramUniform1i(r->disp_rndr.prog, r->disp_rndr.tex_loc, 0);
glUniform2f(r->disp_rndr.display_size_loc, width, height);
glUniform1f(r->disp_rndr.line_offset_loc, line_offset);
#ifdef __ANDROID__
glUniform1i(r->disp_rndr.clip_enable_loc, clip_enable ? 1 : 0);
glUniform4f(r->disp_rndr.clip_rect_loc, clip_x, clip_y, clip_w, clip_h);
#endif
glUniform1i(r->disp_rndr.clip_enable_loc, 0);
render_display_pvideo_overlay(d);
glViewport(0, 0, width, height);
@@ -629,28 +517,30 @@ static void render_display(NV2AState *d, SurfaceBinding *surface)
glDisable(GL_STENCIL_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
#ifndef __ANDROID__ /* glPolygonMode not available in GLES 3.x core */
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
#ifdef __ANDROID__
if (android_force_cpu_blit()) {
android_store_readback(d, surface, width, height);
}
#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, 0, 0);
}
static void gl_fence(void)
{
#ifdef __ANDROID__
/* Shared-context sync objects are still producing invalid-operation
* failures on Adreno. Favor correctness over throughput here. */
glFinish();
#else
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
int result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT,
(GLuint64)(5000000000));
assert(result == GL_CONDITION_SATISFIED || result == GL_ALREADY_SIGNALED);
glDeleteSync(fence);
#endif
}
void pgraph_gl_sync(NV2AState *d)
@@ -677,29 +567,27 @@ void pgraph_gl_sync(NV2AState *d)
/* Wait for queued commands to complete */
#ifdef __ANDROID__
bool force_upload = !tcg_enabled();
if (android_force_cpu_blit() && surface->draw_time == 0) {
force_upload = true;
static unsigned int no_draw_log = 0;
if ((no_draw_log++ % 120) == 0) {
__android_log_print(ANDROID_LOG_WARN, "xemu-android",
"pgraph_gl_sync: forcing upload (no draws yet) vram=0x%x",
(unsigned)surface->vram_addr);
}
}
pgraph_gl_upload_surface_data(d, surface, force_upload);
#else
pgraph_gl_upload_surface_data(d, surface, !tcg_enabled());
GL_ASSERT_NO_ERROR("pgraph_gl_sync: pre-upload");
#endif
pgraph_gl_upload_surface_data(d, surface, !tcg_enabled());
GL_ASSERT_NO_ERROR("pgraph_gl_sync: surface upload");
gl_fence();
GL_ASSERT_NO_ERROR("pgraph_gl_sync: upload fence");
GL_ASSERT_NO_ERROR("pgraph_gl_sync: upload finish");
/* Render framebuffer */
#ifdef __ANDROID__
glo_set_current(g_nv2a_context_render);
render_display(d, surface);
gl_fence();
GL_ASSERT_NO_ERROR("pgraph_gl_sync: render fence");
{
AndroidDisplayGLState state;
glo_set_current(g_nv2a_context_render);
GL_ASSERT_NO_ERROR("pgraph_gl_sync: pre-render");
android_display_capture_gl_state(&state);
render_display(d, surface);
GL_ASSERT_NO_ERROR("pgraph_gl_sync: render display");
android_display_restore_gl_state(&state);
gl_fence();
GL_ASSERT_NO_ERROR("pgraph_gl_sync: render finish");
}
#else
/* Render framebuffer in display context */
glo_set_current(g_nv2a_context_display);
+21 -4
View File
@@ -163,7 +163,6 @@ void pgraph_gl_draw_begin(NV2AState *d)
assert(r->color_binding || r->zeta_binding);
pgraph_gl_bind_textures(d);
pgraph_gl_bind_shaders(pg);
glColorMask(mask_red, mask_green, mask_blue, mask_alpha);
glDepthMask(!!(control_0 & NV_PGRAPH_CONTROL_0_ZWRITEENABLE));
@@ -215,8 +214,10 @@ void pgraph_gl_draw_begin(NV2AState *d)
/* Polygon offset is handled in geometry and fragment shaders explicitly */
glDisable(GL_POLYGON_OFFSET_FILL);
#ifndef __ANDROID__ /* GL_POLYGON_OFFSET_LINE/POINT not valid in GLES 3.x */
glDisable(GL_POLYGON_OFFSET_LINE);
glDisable(GL_POLYGON_OFFSET_POINT);
#endif
/* Depth testing */
if (depth_test) {
@@ -234,8 +235,10 @@ void pgraph_gl_draw_begin(NV2AState *d)
glEnable(GL_DEPTH_CLAMP);
#endif
#ifndef __ANDROID__ /* glProvokingVertex not available in GLES 3.x */
/* Set first vertex convention to match Vulkan default */
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
#endif
if (stencil_test) {
glEnable(GL_STENCIL_TEST);
@@ -281,7 +284,11 @@ void pgraph_gl_draw_begin(NV2AState *d)
glDisable(GL_DITHER);
}
#ifndef __ANDROID__
/* GL_PROGRAM_POINT_SIZE is not a valid enum in GLES 3.x;
* point size from gl_PointSize is always enabled in GLES. */
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
bool anti_aliasing = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_ANTIALIASING), NV_PGRAPH_ANTIALIASING_ENABLE);
@@ -328,6 +335,9 @@ void pgraph_gl_draw_begin(NV2AState *d)
glScissor(xmin, ymin, scissor_width, scissor_height);
/* Visibility testing */
/* GL_SAMPLES_PASSED is desktop-only; GLES has GL_ANY_SAMPLES_PASSED but
* only returns boolean. Skip occlusion queries entirely on Android. */
#ifndef __ANDROID__
if (pg->zpass_pixel_count_enable) {
r->gl_zpass_pixel_count_query_count++;
r->gl_zpass_pixel_count_queries = (GLuint*)g_realloc(
@@ -340,6 +350,7 @@ void pgraph_gl_draw_begin(NV2AState *d)
r->gl_zpass_pixel_count_query_count - 1] = gl_query;
glBeginQuery(GL_SAMPLES_PASSED, gl_query);
}
#endif
}
void pgraph_gl_draw_end(NV2AState *d)
@@ -373,10 +384,12 @@ void pgraph_gl_draw_end(NV2AState *d)
pgraph_gl_flush_draw(d);
/* End of visibility testing */
#ifndef __ANDROID__
if (pg->zpass_pixel_count_enable) {
nv2a_profile_inc_counter(NV2A_PROF_QUERY);
glEndQuery(GL_SAMPLES_PASSED);
}
#endif
pg->draw_time++;
#ifdef __ANDROID__
@@ -400,7 +413,6 @@ void pgraph_gl_flush_draw(NV2AState *d)
if (!(r->color_binding || r->zeta_binding)) {
return;
}
assert(r->shader_binding);
PrimAssemblyState assembly = {
.primitive_mode = pg->primitive_mode,
@@ -426,6 +438,7 @@ void pgraph_gl_flush_draw(NV2AState *d)
pg->draw_arrays_max_count - 1,
false, 0,
pg->draw_arrays_max_count - 1);
pgraph_gl_bind_shaders(pg);
PrimRewrite prim_rw = pgraph_prim_rewrite_ranges(
&r->prim_rewrite_buf, assembly, pg->draw_arrays_start,
@@ -469,6 +482,7 @@ void pgraph_gl_flush_draw(NV2AState *d)
pgraph_gl_bind_vertex_attributes(
d, min_element, max_element, false, 0,
draw_indices[draw_index_count - 1]);
pgraph_gl_bind_shaders(pg);
if (prim_rw.num_indices > 0) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->gl_prim_rewrite_buffer);
@@ -508,10 +522,12 @@ void pgraph_gl_flush_draw(NV2AState *d)
nv2a_profile_inc_counter(NV2A_PROF_INLINE_BUFFERS);
assert(pg->inline_array_length == 0);
if (pg->compressed_attrs) {
if (pg->compressed_attrs || pg->swizzle_attrs || pg->uniform_attrs) {
pg->compressed_attrs = 0;
pgraph_gl_bind_shaders(pg);
pg->uniform_attrs = 0;
pg->swizzle_attrs = 0;
}
pgraph_gl_bind_shaders(pg);
for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
VertexAttribute *attr = &pg->vertex_attributes[i];
@@ -552,6 +568,7 @@ void pgraph_gl_flush_draw(NV2AState *d)
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ARRAYS);
unsigned int index_count = pgraph_gl_bind_inline_array(d);
pgraph_gl_bind_shaders(pg);
PrimRewrite prim_rw = pgraph_prim_rewrite_sequential(
&r->prim_rewrite_buf, assembly, 0, index_count);
+13
View File
@@ -126,7 +126,12 @@ static void pgraph_gl_init(NV2AState *d, Error **errp)
assert(glo_check_extension("GL_ARB_ES2_compatibility"));
#endif
#ifndef __ANDROID__ /* GL_SMOOTH_LINE_WIDTH_RANGE not valid in GLES 3.x */
glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, r->supported_smooth_line_width_range);
#else
r->supported_smooth_line_width_range[0] = 1.0f;
r->supported_smooth_line_width_range[1] = 1.0f;
#endif
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, r->supported_aliased_line_width_range);
pgraph_gl_init_surfaces(pg);
@@ -143,6 +148,14 @@ static void pgraph_gl_init(NV2AState *d, Error **errp)
r->supported_extensions.texture_filter_anisotropic =
glo_check_extension("GL_EXT_texture_filter_anisotropic");
r->supported_extensions.max_texture_max_anisotropy = 1.0f;
if (r->supported_extensions.texture_filter_anisotropic) {
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,
&r->supported_extensions.max_texture_max_anisotropy);
if (r->supported_extensions.max_texture_max_anisotropy < 1.0f) {
r->supported_extensions.max_texture_max_anisotropy = 1.0f;
}
}
}
static void pgraph_gl_finalize(NV2AState *d)
+1
View File
@@ -242,6 +242,7 @@ typedef struct PGRAPHGLState {
struct supported_extensions {
GLboolean texture_filter_anisotropic;
GLfloat max_texture_max_anisotropy;
} supported_extensions;
#ifdef __ANDROID__
+35 -1
View File
@@ -29,6 +29,10 @@
#include "debug.h"
#include "renderer.h"
#ifdef __ANDROID__
#include <android/log.h>
#endif
static GLenum get_gl_primitive_mode(enum ShaderPrimitiveMode primitive_mode)
{
switch (primitive_mode) {
@@ -41,6 +45,31 @@ static GLenum get_gl_primitive_mode(enum ShaderPrimitiveMode primitive_mode)
}
}
static void log_shader_source_with_line_numbers(const char *name,
const char *code)
{
int line_no = 1;
const char *line = code;
while (line && *line) {
const char *line_end = strchr(line, '\n');
size_t len = line_end ? (size_t)(line_end - line) : strlen(line);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "xemu-android",
"%s %4d | %.*s", name, line_no, (int)len, line);
#endif
fprintf(stderr, "%s %4d | %.*s\n", name, line_no, (int)len, line);
if (!line_end) {
break;
}
line = line_end + 1;
line_no++;
}
}
static GLuint create_gl_shader(GLenum gl_shader_type,
const char *code,
const char *name)
@@ -64,7 +93,12 @@ static GLuint create_gl_shader(GLenum gl_shader_type,
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
log = g_malloc(log_length * sizeof(GLchar));
glGetShaderInfoLog(shader, log_length, NULL, log);
fprintf(stderr, "%s\n\n" "nv2a: %s compilation failed: %s\n", code, name, log);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "xemu-android",
"nv2a: %s compilation failed: %s", name, log);
#endif
fprintf(stderr, "nv2a: %s compilation failed: %s\n", name, log);
log_shader_source_with_line_numbers(name, code);
g_free(log);
NV2A_GL_DGROUP_END();
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+13
View File
@@ -80,6 +80,8 @@ void pgraph_gl_bind_vertex_attributes(NV2AState *d, unsigned int min_element,
}
pg->compressed_attrs = 0;
pg->uniform_attrs = 0;
pg->swizzle_attrs = 0;
for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
VertexAttribute *attr = &pg->vertex_attributes[i];
@@ -97,13 +99,21 @@ void pgraph_gl_bind_vertex_attributes(NV2AState *d, unsigned int min_element,
GLenum gl_type;
GLboolean gl_normalize;
bool needs_conversion = false;
bool d3d_swizzle = false;
switch (attr->format) {
case NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_UB_D3D:
gl_type = GL_UNSIGNED_BYTE;
gl_normalize = GL_TRUE;
#ifdef __ANDROID__
gl_count = attr->count;
if (attr->count == 4) {
d3d_swizzle = true;
}
#else
// http://www.opengl.org/registry/specs/ARB/vertex_array_bgra.txt
gl_count = GL_BGRA;
#endif
break;
case NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE_UB_OGL:
gl_type = GL_UNSIGNED_BYTE;
@@ -188,6 +198,9 @@ void pgraph_gl_bind_vertex_attributes(NV2AState *d, unsigned int min_element,
}
glEnableVertexAttribArray(i);
if (d3d_swizzle) {
pg->swizzle_attrs |= (1 << i);
}
last_entry += stride * provoking_element_index;
pgraph_update_inline_value(attr, last_entry);
}
+17 -25
View File
@@ -179,19 +179,10 @@ void pgraph_glsl_set_psh_state(PGRAPHState *pg, PshState *state)
}
}
/* Keep track of whether texture data has been loaded as signed
* normalized integers or not. This dictates whether or not we will need
* to re-map in fragment shader for certain texture modes (e.g.
* bumpenvmap).
*
* FIXME: When signed texture data is loaded as unsigned and remapped in
* fragment shader, there may be interpolation artifacts. Fix this to
* support signed textures more appropriately.
*/
#if 0 // FIXME
psh->snorm_tex[i] = (f.gl_internal_format == GL_RGB8_SNORM)
|| (f.gl_internal_format == GL_RG8_SNORM);
#endif
/* Keep track of textures that are uploaded as signed normalized data.
* Those must not be remapped a second time in the fragment shader. */
state->snorm_tex[i] =
color_format == NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R6G5B5;
state->shadow_map[i] = f.depth;
uint32_t filter = pgraph_reg_r(pg, NV_PGRAPH_TEXFILTER0 + i * 4);
@@ -767,7 +758,7 @@ static void apply_border_adjustment(const struct PixelShader *ps, MString *vars,
mstring_append_fmt(
vars,
"vec3 t%dLogicalSize = vec3(%f, %f, %f);\n"
"%s.xyz = (%s.xyz * t%dLogicalSize + vec3(4, 4, 4)) * vec3(%f, %f, %f);\n",
"%s.xyz = (%s.xyz * t%dLogicalSize + vec3(4.0, 4.0, 4.0)) * vec3(%f, %f, %f);\n",
i, ps->state->border_logical_size[i][0], ps->state->border_logical_size[i][1], ps->state->border_logical_size[i][2],
var_name, var_name, i, ps->state->border_inv_real_size[i][0], ps->state->border_inv_real_size[i][1], ps->state->border_inv_real_size[i][2]);
}
@@ -783,7 +774,7 @@ static void apply_convolution_filter(const struct PixelShader *ps, MString *vars
mstring_append_fmt(vars,
"vec4 t%d = vec4(0.0);\n"
"for (int i = 0; i < 9; i++) {\n"
" vec3 texCoordDelta = vec3(convolution3x3[i], 0);\n"
" vec3 texCoordDelta = vec3(convolution3x3[i], 0.0);\n"
" texCoordDelta.xy /= vec2(textureSize(texSamp%d, 0));\n"
" t%d += textureProj(texSamp%d, %s(pT%d.xyw) + texCoordDelta) * gaussian3x3[i];\n"
"}\n", tex, tex, tex, tex, tex_remap, tex);
@@ -855,22 +846,23 @@ static MString* psh_convert(struct PixelShader *ps)
mstring_append_fmt(preflight,
"float sign1(float x) {\n"
" x *= 255.0;\n"
" return (x-128.0)/127.0;\n"
" float xf = float(x) * 255.0;\n"
" return (xf - 128.0) / 127.0;\n"
"}\n"
"float sign2(float x) {\n"
" x *= 255.0;\n"
" if (x >= 128.0) return (x-255.5)/127.5;\n"
" else return (x+0.5)/127.5;\n"
" float xf = float(x) * 255.0;\n"
" if (xf >= 128.0) return (xf - 255.5) / 127.5;\n"
" else return (xf + 0.5) / 127.5;\n"
"}\n"
"float sign3(float x) {\n"
" x *= 255.0;\n"
" if (x >= 128.0) return (x-256.0)/127.0;\n"
" else return (x)/127.0;\n"
" float xf = float(x) * 255.0;\n"
" if (xf >= 128.0) return (xf - 256.0) / 127.0;\n"
" else return xf / 127.0;\n"
"}\n"
"float sign3_to_0_to_1(float x) {\n"
" if (x >= 0.0) return x/2.0;\n"
" else return 1.0+x/2.0;\n"
" float xf = float(x);\n"
" if (xf >= 0.0) return xf / 2.0;\n"
" else return 1.0 + xf / 2.0;\n"
"}\n"
"vec3 dotmap_zero_to_one(vec4 col) {\n"
" return col.rgb;\n"
+14 -10
View File
@@ -262,6 +262,8 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
static char alpha_source_specular[] = "specular.a";
static char alpha_source_material[] = "material_alpha";
const char *alpha_source = alpha_source_diffuse;
const char *ambient_source_rgb = "diffuse.rgb";
const char *emission_source_rgb = "diffuse.rgb";
if (state->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_MATERIAL) {
alpha_source = alpha_source_material;
} else if (state->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_SPECULAR) {
@@ -269,21 +271,23 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
}
if (state->fixed_function.ambient_src == MATERIAL_COLOR_SRC_MATERIAL) {
mstring_append_fmt(body, "oD0 = vec4(sceneAmbientColor, %s);\n", alpha_source);
ambient_source_rgb = "materialEmissionColor.rgb";
} else if (state->fixed_function.ambient_src == MATERIAL_COLOR_SRC_DIFFUSE) {
mstring_append_fmt(body, "oD0 = vec4(diffuse.rgb, %s);\n", alpha_source);
ambient_source_rgb = "diffuse.rgb";
} else if (state->fixed_function.ambient_src == MATERIAL_COLOR_SRC_SPECULAR) {
mstring_append_fmt(body, "oD0 = vec4(specular.rgb, %s);\n", alpha_source);
ambient_source_rgb = "specular.rgb";
}
mstring_append(body, "oD0.rgb *= materialEmissionColor.rgb;\n");
if (state->fixed_function.emission_src == MATERIAL_COLOR_SRC_MATERIAL) {
mstring_append(body, "oD0.rgb += sceneAmbientColor;\n");
emission_source_rgb = "materialEmissionColor.rgb";
} else if (state->fixed_function.emission_src == MATERIAL_COLOR_SRC_DIFFUSE) {
mstring_append(body, "oD0.rgb += diffuse.rgb;\n");
emission_source_rgb = "diffuse.rgb";
} else if (state->fixed_function.emission_src == MATERIAL_COLOR_SRC_SPECULAR) {
mstring_append(body, "oD0.rgb += specular.rgb;\n");
emission_source_rgb = "specular.rgb";
}
mstring_append_fmt(body, "oD0 = vec4(sceneAmbientColor * %s, %s);\n",
ambient_source_rgb, alpha_source);
mstring_append_fmt(body, "oD0.rgb += %s;\n", emission_source_rgb);
mstring_append(body, "oD1 = vec4(0.0, 0.0, 0.0, specular.a);\n");
@@ -349,7 +353,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
/* https://docs.microsoft.com/en-us/windows/win32/direct3d9/attenuation-and-spotlight-factor#spotlight-factor */
mstring_append_fmt(body,
" vec4 spotDir = lightSpotDirection(%d);\n"
" float invScale = 1/length(spotDir.xyz);\n"
" float invScale = 1.0 / length(spotDir.xyz);\n"
" float cosHalfPhi = -invScale*spotDir.w;\n"
" float cosHalfTheta = invScale + cosHalfPhi;\n"
" float spotDirDotVP = dot(spotDir.xyz, VP);\n"
@@ -485,7 +489,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
" oPos.xy = roundScreenCoords(oPos.xy);\n"
" vec4 vtxPos = vec4(oPos.xy, oPos.z / oPos.w, oPos.w);\n"
" oPos.z = oPos.z / clipRange.y;\n"
" oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.xy = (2.0 * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.xy *= oPos.w;\n"
);
@@ -495,7 +499,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
" float d_e = length(position * modelViewMat0);\n"
" float ptMinSize = min(pointParams[7], 63.875);\n"
" float ptMaxSize = min(pointParams[3] + ptMinSize, 63.875);\n"
" oPts.x = 1/sqrt(pointParams[0] + pointParams[1] * d_e + pointParams[2] * d_e * d_e) + pointParams[6];\n");
" oPts.x = 1.0 / sqrt(pointParams[0] + pointParams[1] * d_e + pointParams[2] * d_e * d_e) + pointParams[6];\n");
mstring_append_fmt(body,
" oPts.x = clamp(oPts.x * pointParams[3] + pointParams[7], ptMinSize, ptMaxSize) * float(%d);\n",
state->surface_scale_factor);
+2 -2
View File
@@ -696,7 +696,7 @@ static const char* vsh_header =
"vec4 _LOG(float src)\n"
"{\n"
" float tmp = abs(src);\n"
" if (tmp == 0.0) { return vec4(-INFINITY, 1.0f, -INFINITY, 1.0f); }\n"
" if (tmp == 0.0) { return vec4(-INFINITY, 1.0, -INFINITY, 1.0); }\n"
" vec4 result;\n"
" result.x = floor(log2(tmp));\n"
" result.y = tmp / exp2(floor(log2(tmp)));\n"
@@ -757,7 +757,7 @@ void pgraph_glsl_gen_vsh_prog(uint16_t version, const uint32_t *tokens,
" oPos.xy = roundScreenCoords(oPos.xy);\n"
" oPos.w = clampAwayZeroInf(oPos.w);\n"
" vec4 vtxPos = oPos;\n"
" oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.xy = (2.0 * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.z = oPos.z / clipRange.y;\n"
/* Undo perspective divide by w.
+1 -1
View File
@@ -229,7 +229,7 @@ MString *pgraph_glsl_gen_vsh(const VshState *state, GenVshGlslOptions opts)
// fractional part and to convert floating-point coordinates by
// by truncating (not flooring).
"vec2 roundScreenCoords(vec2 pos) {\n"
" return trunc(pos * 16.0f) / 16.0f;\n"
" return trunc(pos * 16.0) / 16.0;\n"
"}\n");
pgraph_glsl_get_vtx_header(header, opts.vulkan, state->smooth_shading,
+10 -8
View File
@@ -2487,10 +2487,8 @@ DEF_METHOD_INC(NV097, SET_TEXCOORD3_2F)
do { \
VertexAttribute *attribute = &pg->vertex_attributes[(attr_index)]; \
pgraph_allocate_inline_buffer_vertices(pg, (attr_index)); \
attribute->inline_value[0] = (parameter & 0xFF) / 255.0f; \
attribute->inline_value[1] = ((parameter >> 8) & 0xFF) / 255.0f; \
attribute->inline_value[2] = ((parameter >> 16) & 0xFF) / 255.0f; \
attribute->inline_value[3] = ((parameter >> 24) & 0xFF) / 255.0f; \
pgraph_argb_pack32_to_rgba_float(parameter, \
attribute->inline_value); \
} while (0)
DEF_METHOD_INC(NV097, SET_DIFFUSE_COLOR4UB)
@@ -2917,10 +2915,14 @@ DEF_METHOD_INC(NV097, SET_VERTEX_DATA4UB)
int slot = (method - NV097_SET_VERTEX_DATA4UB) / 4;
VertexAttribute *attribute = &pg->vertex_attributes[slot];
pgraph_allocate_inline_buffer_vertices(pg, slot);
attribute->inline_value[0] = (parameter & 0xFF) / 255.0;
attribute->inline_value[1] = ((parameter >> 8) & 0xFF) / 255.0;
attribute->inline_value[2] = ((parameter >> 16) & 0xFF) / 255.0;
attribute->inline_value[3] = ((parameter >> 24) & 0xFF) / 255.0;
if (slot == NV2A_VERTEX_ATTR_DIFFUSE || slot == NV2A_VERTEX_ATTR_SPECULAR) {
pgraph_argb_pack32_to_rgba_float(parameter, attribute->inline_value);
} else {
attribute->inline_value[0] = (parameter & 0xFF) / 255.0;
attribute->inline_value[1] = ((parameter >> 8) & 0xFF) / 255.0;
attribute->inline_value[2] = ((parameter >> 16) & 0xFF) / 255.0;
attribute->inline_value[3] = ((parameter >> 24) & 0xFF) / 255.0;
}
if (slot == 0) {
pgraph_finish_inline_buffer_vertex(pg);
}

Some files were not shown because too many files have changed in this diff Show More