This commit is contained in:
aenu
2025-06-30 23:28:14 +08:00
parent 8ed88e0aa1
commit 3036869a4c
85 changed files with 2066 additions and 1143 deletions

View File

@@ -5,12 +5,14 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application android:label="@string/app_name"
android:name="aenu.aps3e.Application"
android:allowNativeHeapPointerTagging="false"
android:supportsRtl="true"
android:icon="@drawable/app_icon"
android:isGame="true">
<activity android:name="aenu.aps3e.MainActivity"

View File

@@ -14,30 +14,8 @@ bool operator!=(const mem_map_entry_t& lhs, const mem_map_entry_t& rhs) {
return !(lhs == rhs);
}
static std::vector<mem_map_entry_t> start_entries;
void meminfo_init() {
std::ifstream maps_file("/proc/self/maps");
std::string line;
while (std::getline(maps_file, line)) {
std::istringstream iss(line);
mem_map_entry_t entry;
char dash;
char colon;
iss >> std::hex >> entry.start_addr >> dash >> entry.end_addr;
iss >> entry.permissions;
iss >> std::hex >> entry.offset;
iss >> std::dec >> entry.dev_major >> colon >> entry.dev_minor;
iss >> entry.inode;
std::getline(iss, entry.pathname);
if (!entry.pathname.empty() && entry.pathname[0] == ' ') {
entry.pathname.erase(0, 1);
}
start_entries.push_back(entry);
}
}
std::vector<mem_map_entry_t> meminfo_update() {
std::vector<mem_map_entry_t> meminfo_update(const std::vector<mem_map_entry_t>& origin) {
const std::vector<mem_map_entry_t>& start_entries=origin;
std::vector<mem_map_entry_t> entries;
std::ifstream maps_file("/proc/self/maps");
std::string line;
@@ -118,4 +96,43 @@ float meminfo_sys_mem_usage(float scale){
}
}
return (total_mem - available_mem) *scale/ total_mem;
}
uint64_t meminfo_sys_mem_usage_kb(){
std::ifstream maps_file("/proc/meminfo");
std::string line;
uint64_t total_mem = 0;
uint64_t available_mem = 0;
while (std::getline(maps_file, line)) {
if (line.find("MemTotal:") != std::string::npos) {
sscanf(line.c_str(), "MemTotal: %lu kB", &total_mem);
}
else if (line.find("MemAvailable:") != std::string::npos) {
sscanf(line.c_str(), "MemAvailable: %lu kB", &available_mem);
}
}
return total_mem - available_mem;
}
uint64_t meminfo_gpu_mem_usage_kb(){
std::ifstream maps_file("/proc/meminfo");
std::string line;
uint64_t gpu_totalused = 0;
while (std::getline(maps_file, line)) {
if (line.find("GPUTotalUsed:") != std::string::npos) {
sscanf(line.c_str(), "GPUTotalUsed: %lu kB", &gpu_totalused);
break;
}
}
return gpu_totalused;
}
std::string meminfo_gpu_mem_usage(){
uint64_t gpu_totalused = meminfo_gpu_mem_usage_kb();
if(gpu_totalused){
float gpu_usage = gpu_totalused / 1024.0f/ 1024.0f;
return std::to_string(gpu_usage) + " GB";
}
return "N/A";
}

View File

@@ -19,12 +19,14 @@ struct mem_map_entry_t {
std::string pathname;
};
void meminfo_init();
std::vector<mem_map_entry_t> meminfo_update();
std::vector<mem_map_entry_t> meminfo_update(const std::vector<mem_map_entry_t>& origin={});
uint64_t meminfo_calc_total_mem(const std::vector<mem_map_entry_t>& mem_map);
std::string meminfo_print_calc_total_mem(const std::vector<mem_map_entry_t>& mem_map);
std::string meminfo_to_string(const std::vector<mem_map_entry_t>& mem_map,int step_size=1);
float meminfo_sys_mem_usage(float scale=1.0);
uint64_t meminfo_gpu_mem_usage_kb();
std::string meminfo_gpu_mem_usage();
#endif //APS3E_MEMINFO_H

View File

@@ -565,7 +565,6 @@ target_sources(rpcs3_emu PRIVATE
RSX/rsx_utils.cpp
RSX/rsx_vertex_data.cpp
)
if(NOT ANDROID)
target_sources(rpcs3_emu PRIVATE
RSX/GL/GLCommonDecompiler.cpp
@@ -597,7 +596,6 @@ target_sources(rpcs3_emu PRIVATE
RSX/GL/upscalers/fsr1/fsr_pass.cpp
)
endif()
if(TARGET 3rdparty_vulkan)
target_sources(rpcs3_emu PRIVATE
RSX/VK/upscalers/fsr1/fsr_pass.cpp

View File

@@ -58,6 +58,8 @@ namespace gl
if (!compiled)
{
ensure(!m_src.empty(), "Compute shader is not initialized!");
m_shader.create(::glsl::program_domain::glsl_compute_program, m_src);
m_shader.compile();
@@ -82,6 +84,7 @@ namespace gl
void compute_task::run(gl::command_context& cmd, u32 invocations_x, u32 invocations_y)
{
ensure(compiled && m_program.id() != GL_NONE);
bind_resources();
cmd->use_program(m_program.id());
@@ -393,7 +396,12 @@ namespace gl
m_program.uniforms["output_pitch"] = row_pitch;
m_program.uniforms["region_offset"] = color2i(region.x, region.y);
m_program.uniforms["region_size"] = color2i(region.width, region.height);
#ifdef USE_GLES
m_program.uniforms["is_bgra"] = false;
#else
m_program.uniforms["is_bgra"] = (layout.format == static_cast<GLenum>(gl::texture::format::bgra));
#endif
m_program.uniforms["block_width"] = static_cast<u32>(layout.size);
auto data_view = src->get_view(rsx::default_remap_vector.with_encoding(GL_REMAP_IDENTITY), gl::image_aspect::color);

View File

@@ -381,7 +381,7 @@ namespace gl
template<class T>
T* get_compute_task()
{
u32 index = id_manager::typeinfo::get_index<T>();
u32 index = stx::typeindex<id_manager::typeinfo, T>();
auto &e = g_compute_tasks[index];
if (!e)

View File

@@ -2,6 +2,7 @@
#include "GLDMA.h"
#include "Emu/Memory/vm.h"
#include "Emu/RSX/GL/glutils/common.h"
namespace gl
{

View File

@@ -3,6 +3,8 @@
#include "../rsx_methods.h"
#include "../Common/BufferUtils.h"
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
namespace gl
{
GLenum comparison_op(rsx::comparison_function op)
@@ -153,7 +155,7 @@ void GLGSRender::update_draw_state()
gl_state.depth_func(gl::comparison_op(rsx::method_registers.depth_func()));
}
if (gl::get_driver_caps().EXT_depth_bounds_test && (gl_state.enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
if (gl::get_driver_caps().EXT_depth_bounds_test_supported && (gl_state.enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
{
gl_state.depth_bounds(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
}
@@ -256,6 +258,32 @@ void GLGSRender::update_draw_state()
gl_state.enablei(mrt_blend_enabled[2], GL_BLEND, 2);
gl_state.enablei(mrt_blend_enabled[3], GL_BLEND, 3);
}
// Antialias control
if (backend_config.supports_hw_msaa)
{
gl_state.enable(/*REGS(m_ctx)->msaa_enabled()*/GL_MULTISAMPLE);
gl_state.enable(GL_SAMPLE_MASK);
gl_state.sample_mask(REGS(m_ctx)->msaa_sample_mask());
gl_state.enable(GL_SAMPLE_SHADING);
gl_state.min_sample_shading_rate(1.f);
gl_state.enable(GL_SAMPLE_COVERAGE);
gl_state.sample_coverage(1.f);
}
if (backend_config.supports_hw_a2c)
{
const bool hw_enable = backend_config.supports_hw_a2c_1spp || REGS(m_ctx)->surface_antialias() != rsx::surface_antialiasing::center_1_sample;
gl_state.enable(hw_enable && REGS(m_ctx)->msaa_alpha_to_coverage_enabled(), GL_SAMPLE_ALPHA_TO_COVERAGE);
}
if (backend_config.supports_hw_a2one)
{
gl_state.enable(REGS(m_ctx)->msaa_alpha_to_one_enabled(), GL_SAMPLE_ALPHA_TO_ONE);
}
}
switch (rsx::method_registers.current_draw_clause.primitive)
@@ -307,12 +335,6 @@ void GLGSRender::update_draw_state()
// Clip planes
gl_state.clip_planes((current_vertex_program.output_mask >> CELL_GCM_ATTRIB_OUTPUT_UC0) & 0x3F);
// Sample control
// TODO: MinSampleShading
//gl_state.enable(rsx::method_registers.msaa_enabled(), GL_MULTISAMPLE);
//gl_state.enable(rsx::method_registers.msaa_alpha_to_coverage_enabled(), GL_SAMPLE_ALPHA_TO_COVERAGE);
//gl_state.enable(rsx::method_registers.msaa_alpha_to_one_enabled(), GL_SAMPLE_ALPHA_TO_ONE);
//TODO
//NV4097_SET_ANISO_SPREAD
//NV4097_SET_SPECULAR_ENABLE
@@ -365,6 +387,16 @@ void GLGSRender::load_texture_env()
{
m_graphics_state |= rsx::fragment_program_state_dirty;
}
if (const auto texture_format = tex.format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN);
sampler_state->format_class != rsx::classify_format(texture_format) &&
(texture_format == CELL_GCM_TEXTURE_A8R8G8B8 || texture_format == CELL_GCM_TEXTURE_D8R8G8B8))
{
// Depth format redirected to BGRA8 resample stage. Do not filter to avoid bits leaking.
// If accurate graphics are desired, force a bitcast to COLOR as a workaround.
m_fs_sampler_states[i].set_parameteri(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
m_fs_sampler_states[i].set_parameteri(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
}
else
@@ -513,7 +545,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
if (vertex_state & rsx::vertex_arrays_changed)
{
analyse_inputs_interleaved(m_vertex_layout);
m_draw_processor.analyse_inputs_interleaved(m_vertex_layout, current_vp_metadata);
}
else if (vertex_state & rsx::vertex_base_changed)
{
@@ -537,7 +569,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
if (vertex_state && !m_vertex_layout.validate())
{
// No vertex inputs enabled
// Execute remainining pipeline barriers with NOP draw
// Execute remaining pipeline barriers with NOP draw
do
{
draw_call.execute_pipeline_dependencies(m_ctx);
@@ -577,15 +609,19 @@ void GLGSRender::emit_geometry(u32 sub_index)
if (!upload_info.index_info)
{
if (draw_call.is_single_draw())
if (draw_call.is_trivial_instanced_draw)
{
glDrawArraysInstanced(draw_mode, 0, upload_info.vertex_draw_count, draw_call.pass_count());
}
else if (draw_call.is_single_draw())
{
glDrawArrays(draw_mode, 0, upload_info.vertex_draw_count);
}
else
{
const auto subranges = draw_call.get_subranges();
const auto& subranges = draw_call.get_subranges();
const auto draw_count = subranges.size();
const auto driver_caps = gl::get_driver_caps();
const auto& driver_caps = gl::get_driver_caps();
bool use_draw_arrays_fallback = false;
m_scratch_buffer.resize(draw_count * 24);
@@ -595,7 +631,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
u32 first = 0;
u32 dst_index = 0;
for (const auto &range : subranges)
for (const auto& range : subranges)
{
firsts[dst_index] = first;
counts[dst_index] = range.count;
@@ -603,7 +639,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
if (driver_caps.vendor_AMD && (first + range.count) > (0x100000 >> 2))
{
//Unlikely, but added here in case the identity buffer is not large enough somehow
// Unlikely, but added here in case the identity buffer is not large enough somehow
use_draw_arrays_fallback = true;
break;
}
@@ -613,7 +649,7 @@ void GLGSRender::emit_geometry(u32 sub_index)
if (use_draw_arrays_fallback)
{
//MultiDrawArrays is broken on some primitive types using AMD. One known type is GL_TRIANGLE_STRIP but there could be more
// MultiDrawArrays is broken on some primitive types using AMD. One known type is GL_TRIANGLE_STRIP but there could be more
for (u32 n = 0; n < draw_count; ++n)
{
glDrawArrays(draw_mode, firsts[n], counts[n]);
@@ -621,13 +657,13 @@ void GLGSRender::emit_geometry(u32 sub_index)
}
else if (driver_caps.vendor_AMD)
{
//Use identity index buffer to fix broken vertexID on AMD
// Use identity index buffer to fix broken vertexID on AMD
m_identity_index_buffer->bind();
glMultiDrawElements(draw_mode, counts, GL_UNSIGNED_INT, offsets, static_cast<GLsizei>(draw_count));
}
else
{
//Normal render
// Normal render
glMultiDrawArrays(draw_mode, firsts, counts, static_cast<GLsizei>(draw_count));
}
}
@@ -645,7 +681,11 @@ void GLGSRender::emit_geometry(u32 sub_index)
m_index_ring_buffer->bind();
if (draw_call.is_single_draw())
if (draw_call.is_trivial_instanced_draw)
{
glDrawElementsInstanced(draw_mode, upload_info.vertex_draw_count, index_type, reinterpret_cast<GLvoid*>(u64{ index_offset }), draw_call.pass_count());
}
else if (draw_call.is_single_draw())
{
glDrawElements(draw_mode, upload_info.vertex_draw_count, index_type, reinterpret_cast<GLvoid*>(u64{index_offset}));
}
@@ -694,6 +734,7 @@ void GLGSRender::begin()
if (m_graphics_state & rsx::pipeline_state::invalidate_pipeline_bits)
{
// Shaders need to be reloaded.
m_prev_program = m_program;
m_program = nullptr;
}
}
@@ -709,10 +750,7 @@ void GLGSRender::end()
return;
}
if (m_graphics_state & (rsx::pipeline_state::fragment_program_ucode_dirty | rsx::pipeline_state::vertex_program_ucode_dirty))
{
analyse_current_rsx_pipeline();
}
analyse_current_rsx_pipeline();
m_frame_stats.setup_time += m_profiler.duration();
@@ -758,13 +796,20 @@ void GLGSRender::end()
m_program->validate();
}
rsx::method_registers.current_draw_clause.begin();
auto& draw_call = REGS(m_ctx)->current_draw_clause;
draw_call.begin();
u32 subdraw = 0u;
do
{
emit_geometry(subdraw++);
if (draw_call.is_trivial_instanced_draw)
{
// We already completed. End the draw.
draw_call.end();
}
}
while (rsx::method_registers.current_draw_clause.next());
while (draw_call.next());
m_rtts.on_write(m_framebuffer_layout.color_write_enabled, m_framebuffer_layout.zeta_write_enabled);
@@ -776,6 +821,7 @@ void GLGSRender::end()
m_vertex_layout_buffer->notify();
m_fragment_constants_buffer->notify();
m_transform_constants_buffer->notify();
m_instancing_ring_buffer->notify();
m_frame_stats.setup_time += m_profiler.duration();

View File

@@ -3,8 +3,8 @@
#include "Emu/system_config.h"
#include "GLCommonDecompiler.h"
#include "../GCM.h"
#include "../Program/GLSLCommon.h"
#include "../RSXThread.h"
std::string GLFragmentDecompilerThread::getFloatTypeName(usz elementCount)
{
@@ -33,7 +33,7 @@ void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS)
if (device_props.has_native_half_support)
{
const auto driver_caps = gl::get_driver_caps();
const auto& driver_caps = gl::get_driver_caps();
if (driver_caps.NV_gpu_shader5_supported)
{
required_extensions.push_back("GL_NV_gpu_shader5");
@@ -44,6 +44,21 @@ void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS)
}
}
if (properties.multisampled_sampler_mask)
{
// Requires this extension or GLSL 450
const auto& driver_caps = gl::get_driver_caps();
if (driver_caps.glsl_version.version >= 450)
{
gl_version = 450;
}
else
{
ensure(driver_caps.ARB_shader_texture_image_samples_supported, "MSAA support on OpenGL requires a driver running OpenGL 4.5 or supporting GL_ARB_shader_texture_image_samples.");
required_extensions.push_back("GL_ARB_shader_texture_image_samples");
}
}
if (m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION)
{
gl_version = std::max(gl_version, 450);
@@ -110,10 +125,14 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
const auto mask = (1 << index);
if (properties.redirected_sampler_mask & mask)
if (properties.multisampled_sampler_mask & mask)
{
// Provide a stencil view of the main resource for the S channel
OS << "uniform u" << samplerType << " " << PI.name << "_stencil;\n";
if (samplerType != "sampler1D" && samplerType != "sampler2D")
{
rsx_log.error("Unexpected multisampled image type '%s'", samplerType);
}
samplerType = "sampler2DMS";
}
else if (properties.shadow_sampler_mask & mask)
{
@@ -127,6 +146,12 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
}
}
if (properties.redirected_sampler_mask & mask)
{
// Provide a stencil view of the main resource for the S channel
OS << "uniform u" << samplerType << " " << PI.name << "_stencil;\n";
}
OS << "uniform " << samplerType << " " << PI.name << ";\n";
}
}
@@ -188,11 +213,12 @@ void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
m_shader_props.require_wpos = !!(properties.in_register_mask & in_wpos);
m_shader_props.require_texture_ops = properties.has_tex_op;
m_shader_props.require_tex_shadow_ops = properties.shadow_sampler_mask != 0;
m_shader_props.require_msaa_ops = properties.multisampled_sampler_mask != 0;
m_shader_props.require_texture_expand = properties.has_exp_tex_op;
m_shader_props.require_srgb_to_linear = properties.has_upg;
m_shader_props.require_linear_to_srgb = properties.has_pkg;
m_shader_props.require_fog_read = properties.in_register_mask & in_fogc;
m_shader_props.emulate_coverage_tests = true; // g_cfg.video.antialiasing_level == msaa_level::none;
m_shader_props.emulate_coverage_tests = !rsx::get_renderer_backend_config().supports_hw_a2c_1spp;
m_shader_props.emulate_shadow_compare = device_props.emulate_depth_compare;
m_shader_props.low_precision_tests = ::gl::get_driver_caps().vendor_NVIDIA && !(m_prog.ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION);
m_shader_props.disable_early_discard = !::gl::get_driver_caps().vendor_NVIDIA;
@@ -340,7 +366,7 @@ void GLFragmentProgram::Decompile(const RSXFragmentProgram& prog)
if (g_cfg.video.shader_precision == gpu_preset_level::low)
{
const auto driver_caps = gl::get_driver_caps();
const auto& driver_caps = gl::get_driver_caps();
decompiler.device_props.has_native_half_support = driver_caps.NV_gpu_shader5_supported || driver_caps.AMD_gpu_shader_half_float_supported;
decompiler.device_props.has_low_precision_rounding = driver_caps.vendor_NVIDIA;
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include "../Program/FragmentProgramDecompiler.h"
#include "../Program/GLSLTypes.h"
#include "GLHelpers.h"
#include "glutils/program.h"
namespace glsl

View File

@@ -4,9 +4,11 @@
#include "GLGSRender.h"
#include "GLCompute.h"
#include "GLDMA.h"
#include "GLResolveHelper.h"
#include "Emu/Memory/vm_locking.h"
#include "Emu/RSX/rsx_methods.h"
#include "Emu/RSX/Host/MM.h"
#include "Emu/RSX/Host/RSXDMAWriter.h"
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
@@ -38,17 +40,31 @@ u64 GLGSRender::get_cycles()
GLGSRender::GLGSRender(utils::serial* ar) noexcept : GSRender(ar)
{
m_shaders_cache = std::make_unique<gl::shader_cache>(m_prog_buffer, "opengl", "v1.94");
m_shaders_cache = std::make_unique<gl::shader_cache>(m_prog_buffer, "opengl", "v1.95");
if (g_cfg.video.disable_vertex_cache)
m_vertex_cache = std::make_unique<gl::null_vertex_cache>();
else
m_vertex_cache = std::make_unique<gl::weak_vertex_cache>();
backend_config.supports_hw_a2c = false;
backend_config.supports_hw_a2one = false;
backend_config.supports_multidraw = true;
backend_config.supports_normalized_barycentrics = true;
if (g_cfg.video.antialiasing_level != msaa_level::none)
{
backend_config.supports_hw_msaa = true;
backend_config.supports_hw_a2c = true;
backend_config.supports_hw_a2c_1spp = false; // In OGL A2C is implicitly disabled at 1spp
backend_config.supports_hw_a2one = true;
}
}
GLGSRender::~GLGSRender()
{
if (m_frame)
{
m_frame->reset();
}
}
extern CellGcmContextData current_context;
@@ -132,15 +148,15 @@ void GLGSRender::on_init_thread()
rsx_log.success("GL VERSION: %s", reinterpret_cast<const char*>(glGetString(GL_VERSION)));
rsx_log.success("GLSL VERSION: %s", reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)));
auto& gl_caps = gl::get_driver_caps();
const auto& gl_caps = gl::get_driver_caps();
std::vector<std::string> exception_reasons;
if (!gl_caps.ARB_texture_buffer_supported)
if (!gl_caps.ARB_texture_buffer_object_supported)
{
exception_reasons.push_back("GL_ARB_texture_buffer_object is required but not supported by your GPU");
}
if (!gl_caps.ARB_dsa_supported && !gl_caps.EXT_dsa_supported)
if (!gl_caps.ARB_direct_state_access_supported && !gl_caps.EXT_direct_state_access_supported)
{
exception_reasons.push_back("GL_ARB_direct_state_access or GL_EXT_direct_state_access is required but not supported by your GPU");
}
@@ -182,7 +198,7 @@ void GLGSRender::on_init_thread()
backend_config.supports_normalized_barycentrics = false;
}
if (gl_caps.AMD_pinned_memory && g_cfg.video.host_label_synchronization)
if (gl_caps.AMD_pinned_memory_supported && g_cfg.video.host_label_synchronization)
{
backend_config.supports_host_gpu_labels = true;
@@ -220,13 +236,13 @@ void GLGSRender::on_init_thread()
// Array stream buffer
{
m_gl_persistent_stream_buffer = std::make_unique<gl::texture>(GL_TEXTURE_BUFFER, 0, 0, 0, 0, GL_R8UI);
m_gl_persistent_stream_buffer = std::make_unique<gl::texture>(GL_TEXTURE_BUFFER, 0, 0, 0, 0, 0, GL_R8UI, RSX_FORMAT_CLASS_DONT_CARE);
gl_state.bind_texture(GL_STREAM_BUFFER_START + 0, GL_TEXTURE_BUFFER, m_gl_persistent_stream_buffer->id());
}
// Register stream buffer
{
m_gl_volatile_stream_buffer = std::make_unique<gl::texture>(GL_TEXTURE_BUFFER, 0, 0, 0, 0, GL_R8UI);
m_gl_volatile_stream_buffer = std::make_unique<gl::texture>(GL_TEXTURE_BUFFER, 0, 0, 0, 0, 0, GL_R8UI, RSX_FORMAT_CLASS_DONT_CARE);
gl_state.bind_texture(GL_STREAM_BUFFER_START + 1, GL_TEXTURE_BUFFER, m_gl_volatile_stream_buffer->id());
}
@@ -235,19 +251,19 @@ void GLGSRender::on_init_thread()
std::array<u32, 8> pixeldata = { 0, 0, 0, 0, 0, 0, 0, 0 };
// 1D
auto tex1D = std::make_unique<gl::texture>(GL_TEXTURE_1D, 1, 1, 1, 1, GL_RGBA8);
auto tex1D = std::make_unique<gl::texture>(GL_TEXTURE_1D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex1D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
// 2D
auto tex2D = std::make_unique<gl::texture>(GL_TEXTURE_2D, 1, 1, 1, 1, GL_RGBA8);
auto tex2D = std::make_unique<gl::texture>(GL_TEXTURE_2D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex2D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
// 3D
auto tex3D = std::make_unique<gl::texture>(GL_TEXTURE_3D, 1, 1, 1, 1, GL_RGBA8);
auto tex3D = std::make_unique<gl::texture>(GL_TEXTURE_3D, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex3D->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
// CUBE
auto texCUBE = std::make_unique<gl::texture>(GL_TEXTURE_CUBE_MAP, 1, 1, 1, 1, GL_RGBA8);
auto texCUBE = std::make_unique<gl::texture>(GL_TEXTURE_CUBE_MAP, 1, 1, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
texCUBE->copy_from(pixeldata.data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
m_null_textures[GL_TEXTURE_1D] = std::move(tex1D);
@@ -280,6 +296,7 @@ void GLGSRender::on_init_thread()
m_fragment_instructions_buffer = std::make_unique<gl::legacy_ring_buffer>();
m_raster_env_ring_buffer = std::make_unique<gl::legacy_ring_buffer>();
m_scratch_ring_buffer = std::make_unique<gl::legacy_ring_buffer>();
m_instancing_ring_buffer = std::make_unique<gl::legacy_ring_buffer>();
}
else
{
@@ -295,6 +312,7 @@ void GLGSRender::on_init_thread()
m_fragment_instructions_buffer = std::make_unique<gl::ring_buffer>();
m_raster_env_ring_buffer = std::make_unique<gl::ring_buffer>();
m_scratch_ring_buffer = std::make_unique<gl::ring_buffer>();
m_instancing_ring_buffer = std::make_unique<gl::ring_buffer>();
}
m_attrib_ring_buffer->create(gl::buffer::target::texture, 256 * 0x100000);
@@ -307,6 +325,7 @@ void GLGSRender::on_init_thread()
m_vertex_layout_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_raster_env_ring_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_scratch_ring_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
m_instancing_ring_buffer->create(gl::buffer::target::ssbo, 128 * 0x100000);
if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)
{
@@ -414,6 +433,7 @@ void GLGSRender::on_exit()
gl::destroy_compute_tasks();
gl::destroy_overlay_passes();
gl::clear_dma_resources();
gl::clear_resolve_helpers();
gl::destroy_global_texture_resources();
@@ -530,6 +550,11 @@ void GLGSRender::on_exit()
m_scratch_ring_buffer->remove();
}
if (m_instancing_ring_buffer)
{
m_instancing_ring_buffer->remove();
}
m_null_textures.clear();
m_gl_texture_cache.destroy();
m_ui_renderer.destroy();
@@ -753,19 +778,38 @@ bool GLGSRender::load_program()
if (shadermode == shader_mode::interpreter_only)
{
m_program = m_shader_interpreter.get(current_fp_metadata);
m_program = m_shader_interpreter.get(
current_fp_metadata,
current_vertex_program.ctrl,
current_fragment_program.ctrl);
return true;
}
}
const bool was_interpreter = m_shader_interpreter.is_interpreter(m_program);
m_vertex_prog = nullptr;
m_fragment_prog = nullptr;
if (shadermode != shader_mode::interpreter_only) [[likely]]
{
if (g_cfg.video.debug_overlay)
{
m_frame_stats.program_cache_lookups_total += 2;
if (m_program_cache_hint.has_fragment_program())
{
m_frame_stats.program_cache_lookups_ellided++;
}
if (m_program_cache_hint.has_vertex_program())
{
m_frame_stats.program_cache_lookups_ellided++;
}
}
void* pipeline_properties = nullptr;
std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer.get_graphics_pipeline(current_vertex_program, current_fragment_program, pipeline_properties,
std::tie(m_program, m_vertex_prog, m_fragment_prog) = m_prog_buffer.get_graphics_pipeline(
&m_program_cache_hint,
current_vertex_program,
current_fragment_program,
pipeline_properties,
shadermode != shader_mode::recompiler, true);
if (m_prog_buffer.check_cache_missed())
@@ -787,15 +831,35 @@ bool GLGSRender::load_program()
m_program = nullptr;
}
if (!m_program && (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only))
if (shadermode == shader_mode::async_with_interpreter || shadermode == shader_mode::interpreter_only)
{
// Fall back to interpreter
m_program = m_shader_interpreter.get(current_fp_metadata);
if (was_interpreter != m_shader_interpreter.is_interpreter(m_program))
const bool is_interpreter = !m_program;
const bool was_interpreter = m_shader_interpreter.is_interpreter(m_prev_program);
// First load the next program if not available
if (!m_program)
{
m_program = m_shader_interpreter.get(
current_fp_metadata,
current_vertex_program.ctrl,
current_fragment_program.ctrl);
// Program has changed, reupload
m_interpreter_state = rsx::invalidate_pipeline_bits;
}
// If swapping between interpreter and recompiler, we need to adjust some flags to reupload data as needed.
if (is_interpreter != was_interpreter)
{
// Always reupload transform constants when going between interpreter and recompiler
m_graphics_state |= rsx::transform_constants_dirty;
// Always reload fragment constansts when moving from interpreter back to recompiler.
if (was_interpreter)
{
m_graphics_state |= rsx::fragment_constants_dirty;
}
}
}
return m_program != nullptr;
@@ -816,7 +880,8 @@ void GLGSRender::load_program_env()
const bool update_fragment_env = m_graphics_state & rsx::pipeline_state::fragment_state_dirty;
const bool update_fragment_texture_env = m_graphics_state & rsx::pipeline_state::fragment_texture_state_dirty;
const bool update_instruction_buffers = !!m_interpreter_state && m_shader_interpreter.is_interpreter(m_program);
const bool update_raster_env = rsx::method_registers.polygon_stipple_enabled() && (m_graphics_state & rsx::pipeline_state::polygon_stipple_pattern_dirty);
const bool update_raster_env = REGS(m_ctx)->polygon_stipple_enabled() && (m_graphics_state & rsx::pipeline_state::polygon_stipple_pattern_dirty);
const bool update_instancing_data = REGS(m_ctx)->current_draw_clause.is_trivial_instanced_draw;
if (manually_flush_ring_buffers)
{
@@ -826,6 +891,7 @@ void GLGSRender::load_program_env()
if (update_fragment_constants) m_fragment_constants_buffer->reserve_storage_on_heap(utils::align(fragment_constants_size, 256));
if (update_transform_constants) m_transform_constants_buffer->reserve_storage_on_heap(8192);
if (update_raster_env) m_raster_env_ring_buffer->reserve_storage_on_heap(128);
if (update_instancing_data) m_instancing_ring_buffer->reserve_storage_on_heap(8192 * REGS(m_ctx)->current_draw_clause.pass_count());
if (update_instruction_buffers)
{
@@ -839,8 +905,8 @@ void GLGSRender::load_program_env()
// Vertex state
auto mapping = m_vertex_env_buffer->alloc_from_heap(144, m_uniform_buffer_offset_align);
auto buf = static_cast<u8*>(mapping.first);
fill_scale_offset_data(buf, false);
fill_user_clip_data(buf + 64);
m_draw_processor.fill_scale_offset_data(buf, false);
m_draw_processor.fill_user_clip_data(buf + 64);
*(reinterpret_cast<u32*>(buf + 128)) = rsx::method_registers.transform_branch_bits();
*(reinterpret_cast<f32*>(buf + 132)) = rsx::method_registers.point_size() * rsx::get_resolution_scale();
*(reinterpret_cast<f32*>(buf + 136)) = rsx::method_registers.clip_min();
@@ -849,6 +915,33 @@ void GLGSRender::load_program_env()
m_vertex_env_buffer->bind_range(GL_VERTEX_PARAMS_BIND_SLOT, mapping.second, 144);
}
if (update_instancing_data)
{
// Combines transform load + instancing lookup table
const auto alignment = m_min_ssbo_alignment;
u32 indirection_table_offset = 0;
u32 constants_data_table_offset = 0;
rsx::io_buffer indirection_table_buf([&](usz size) -> std::pair<void*, usz>
{
const auto mapping = m_instancing_ring_buffer->alloc_from_heap(static_cast<u32>(size), alignment);
indirection_table_offset = mapping.second;
return mapping;
});
rsx::io_buffer constants_array_buf([&](usz size) -> std::pair<void*, usz>
{
const auto mapping = m_instancing_ring_buffer->alloc_from_heap(static_cast<u32>(size), alignment);
constants_data_table_offset = mapping.second;
return mapping;
});
m_draw_processor.fill_constants_instancing_buffer(indirection_table_buf, constants_array_buf, m_vertex_prog);
m_instancing_ring_buffer->bind_range(GL_INSTANCING_LUT_BIND_SLOT, indirection_table_offset, ::size32(indirection_table_buf));
m_instancing_ring_buffer->bind_range(GL_INSTANCING_XFORM_CONSTANTS_SLOT, constants_data_table_offset, ::size32(constants_array_buf));
}
if (update_transform_constants)
{
// Vertex constants
@@ -869,7 +962,7 @@ void GLGSRender::load_program_env()
}
}
if (update_fragment_constants && !update_instruction_buffers)
if (update_fragment_constants && !m_shader_interpreter.is_interpreter(m_program))
{
// Fragment constants
auto mapping = m_fragment_constants_buffer->alloc_from_heap(fragment_constants_size, m_uniform_buffer_offset_align);
@@ -886,7 +979,7 @@ void GLGSRender::load_program_env()
// Fragment state
auto mapping = m_fragment_env_buffer->alloc_from_heap(32, m_uniform_buffer_offset_align);
auto buf = static_cast<u8*>(mapping.first);
fill_fragment_state_buffer(buf, current_fragment_program);
m_draw_processor.fill_fragment_state_buffer(buf, current_fragment_program);
m_fragment_env_buffer->bind_range(GL_FRAGMENT_STATE_BIND_SLOT, mapping.second, 32);
}
@@ -961,6 +1054,7 @@ void GLGSRender::load_program_env()
if (update_fragment_constants) m_fragment_constants_buffer->unmap();
if (update_transform_constants) m_transform_constants_buffer->unmap();
if (update_raster_env) m_raster_env_ring_buffer->unmap();
if (update_instancing_data) m_instancing_ring_buffer->unmap();
if (update_instruction_buffers)
{
@@ -969,17 +1063,35 @@ void GLGSRender::load_program_env()
}
}
m_graphics_state.clear(
rsx::flags32_t handled_flags =
rsx::pipeline_state::fragment_state_dirty |
rsx::pipeline_state::vertex_state_dirty |
rsx::pipeline_state::transform_constants_dirty |
rsx::pipeline_state::fragment_constants_dirty |
rsx::pipeline_state::fragment_texture_state_dirty);
rsx::pipeline_state::fragment_texture_state_dirty;
if (update_fragment_constants && !m_shader_interpreter.is_interpreter(m_program))
{
handled_flags |= rsx::pipeline_state::fragment_constants_dirty;
}
if (m_shader_interpreter.is_interpreter(m_program))
{
ensure(m_transform_constants_buffer->bound_range().second >= 468 * 16);
}
m_graphics_state.clear(handled_flags);
}
bool GLGSRender::is_current_program_interpreted() const
{
return m_program && m_shader_interpreter.is_interpreter(m_program);
}
void GLGSRender::upload_transform_constants(const rsx::io_buffer& buffer)
{
const usz transform_constants_size = (!m_vertex_prog || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
const bool is_interpreter = m_shader_interpreter.is_interpreter(m_program);
const usz transform_constants_size = (is_interpreter || m_vertex_prog->has_indexed_constants) ? 8192 : m_vertex_prog->constant_ids.size() * 16;
if (transform_constants_size)
{
const auto constant_ids = (transform_constants_size == 8192)
@@ -987,7 +1099,7 @@ void GLGSRender::upload_transform_constants(const rsx::io_buffer& buffer)
: std::span<const u16>(m_vertex_prog->constant_ids);
buffer.reserve(transform_constants_size);
fill_vertex_program_constants_data(buffer.data(), constant_ids);
m_draw_processor.fill_vertex_program_constants_data(buffer.data(), constant_ids);
}
}
@@ -1006,7 +1118,14 @@ void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
buf[1] = upload_info.vertex_index_offset;
buf += 4;
fill_vertex_layout_state(m_vertex_layout, upload_info.first_vertex, upload_info.allocated_vertex_count, reinterpret_cast<s32*>(buf), upload_info.persistent_mapping_offset, upload_info.volatile_mapping_offset);
m_draw_processor.fill_vertex_layout_state(
m_vertex_layout,
current_vp_metadata,
upload_info.first_vertex,
upload_info.allocated_vertex_count,
reinterpret_cast<s32*>(buf),
upload_info.persistent_mapping_offset,
upload_info.volatile_mapping_offset);
m_vertex_layout_buffer->bind_range(GL_VERTEX_LAYOUT_BIND_SLOT, mapping.second, 128 + 16);
@@ -1018,13 +1137,19 @@ void GLGSRender::update_vertex_env(const gl::vertex_upload_info& upload_info)
void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 count)
{
if (!m_vertex_prog)
if (!m_program || !m_vertex_prog)
{
// Shouldn't be reachable, but handle it correctly anyway
m_graphics_state |= rsx::pipeline_state::transform_constants_dirty;
return;
}
if (!m_vertex_prog->overlaps_constants_range(index, count))
{
// Nothing meaningful to us
return;
}
std::pair<u32, u32> data_range {};
void* data_source = nullptr;
const auto bound_range = m_transform_constants_buffer->bound_range();
@@ -1038,7 +1163,7 @@ void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
data_range = { bound_range.first + byte_offset, byte_count};
data_source = &REGS(ctx)->transform_constants[index];
}
else if (auto xform_id = m_vertex_prog->TranslateConstantsRange(index, count); xform_id >= 0)
else if (auto xform_id = m_vertex_prog->translate_constants_range(index, count); xform_id >= 0)
{
const auto write_offset = xform_id * 16;
const auto byte_count = count * 16;
@@ -1082,6 +1207,8 @@ void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
{
rsx::mm_flush(address);
const bool can_flush = is_current_thread();
const rsx::invalidation_cause cause = is_writing
? (can_flush ? rsx::invalidation_cause::write : rsx::invalidation_cause::deferred_write)

View File

@@ -1,15 +1,15 @@
#pragma once
#include "Emu/RSX/GSRender.h"
#include "GLHelpers.h"
#include "GLTexture.h"
#include "GLTextureCache.h"
#include "GLRenderTargets.h"
#include "GLProgramBuffer.h"
#include "GLOverlays.h"
#include "GLShaderInterpreter.h"
#include "Emu/RSX/rsx_cache.h"
#include <optional>
#include <unordered_map>
#include <thread>
#include "glutils/ring_buffer.h"
#include "upscalers/upscaling.h"
@@ -78,6 +78,7 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
gl::sampler_state m_vs_sampler_states[rsx::limits::vertex_textures_count]; // Vertex textures
gl::glsl::program *m_program = nullptr;
gl::glsl::program* m_prev_program = nullptr;
const GLFragmentProgram *m_fragment_prog = nullptr;
const GLVertexProgram *m_vertex_prog = nullptr;
@@ -104,6 +105,7 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
std::unique_ptr<gl::ring_buffer> m_vertex_instructions_buffer;
std::unique_ptr<gl::ring_buffer> m_fragment_instructions_buffer;
std::unique_ptr<gl::ring_buffer> m_raster_env_ring_buffer;
std::unique_ptr<gl::ring_buffer> m_instancing_ring_buffer;
// Identity buffer used to fix broken gl_VertexID on ATI stack
std::unique_ptr<gl::buffer> m_identity_index_buffer;
@@ -116,6 +118,7 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
GLint m_min_texbuffer_alignment = 256;
GLint m_uniform_buffer_offset_align = 256;
GLint m_min_ssbo_alignment = 256;
GLint m_max_texbuffer_size = 65536;
bool manually_flush_ring_buffers = false;
@@ -142,8 +145,6 @@ class GLGSRender : public GSRender, public ::rsx::reports::ZCULL_control
shared_mutex m_sampler_mutex;
atomic_t<bool> m_samplers_dirty = {true};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::fragment_textures_count> fs_sampler_state = {};
std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, rsx::limits::vertex_textures_count> vs_sampler_state = {};
std::unordered_map<GLenum, std::unique_ptr<gl::texture>> m_null_textures;
rsx::simple_array<u8> m_scratch_buffer;
@@ -159,6 +160,7 @@ public:
GLGSRender(utils::serial* ar) noexcept;
GLGSRender() noexcept : GLGSRender(nullptr) {}
virtual ~GLGSRender();
private:
@@ -205,6 +207,9 @@ public:
// GRAPH backend
void patch_transform_constants(rsx::context* ctx, u32 index, u32 count) override;
// Misc
bool is_current_program_interpreted() const override;
protected:
void clear_surface(u32 arg) override;
void begin() override;

View File

@@ -1,10 +1,7 @@
#include "stdafx.h"
#include "GLHelpers.h"
#include "GLTexture.h"
#include "GLCompute.h"
#include "util/logs.hpp"
#include "../Common/simple_array.hpp"
#include <unordered_map>
namespace gl

View File

@@ -1,8 +1,8 @@
#include "GLOverlays.h"
#include "Emu/system_config.h"
#include "../rsx_utils.h"
#include "Utilities/StrUtil.h"
#include "../Program/RSXOverlay.h"
#include "Emu/Cell/timers.hpp"
namespace gl
{
@@ -23,6 +23,8 @@ namespace gl
{
if (!compiled)
{
ensure(!fs_src.empty() && !vs_src.empty(), "Shaders have not been initialized.");
fs.create(::glsl::program_domain::glsl_fragment_program, fs_src);
fs.compile();
@@ -34,6 +36,8 @@ namespace gl
program_handle.attach(fs);
program_handle.link();
ensure(program_handle.id());
fbo.create();
m_sampler.create();
@@ -75,7 +79,7 @@ namespace gl
}
}
void overlay_pass::emit_geometry()
void overlay_pass::emit_geometry(gl::command_context& /*cmd*/)
{
int old_vao;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
@@ -88,11 +92,7 @@ namespace gl
void overlay_pass::run(gl::command_context& cmd, const areau& region, GLuint target_texture, GLuint image_aspect_bits, bool enable_blending)
{
if (!compiled)
{
rsx_log.error("You must initialize overlay passes with create() before calling run()");
return;
}
ensure(compiled && program_handle.id() != GL_NONE, "You must initialize overlay passes with create() before calling run()");
GLint viewport[4];
std::unique_ptr<fbo::save_binding_state> save_fbo;
@@ -111,6 +111,10 @@ namespace gl
fbo.draw_buffer(fbo.no_color);
fbo.depth = target_texture;
break;
case gl::image_aspect::stencil:
fbo.draw_buffer(fbo.no_color);
fbo.depth_stencil = target_texture;
break;
case gl::image_aspect::depth | gl::image_aspect::stencil:
fbo.draw_buffer(fbo.no_color);
fbo.depth_stencil = target_texture;
@@ -176,7 +180,7 @@ namespace gl
cmd->use_program(program_handle.id());
on_load();
bind_resources();
emit_geometry();
emit_geometry(cmd);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
@@ -216,10 +220,10 @@ namespace gl
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid)
{
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, GL_RGBA8);
tex->copy_from(desc->data, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, 1, GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
const GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
auto result = view.get();
@@ -230,7 +234,7 @@ namespace gl
}
else
{
u64 key = reinterpret_cast<u64>(desc);
const u64 key = reinterpret_cast<u64>(desc);
temp_image_cache[key] = std::make_pair(owner_uid, std::move(tex));
temp_view_cache[key] = std::move(view);
}
@@ -245,7 +249,7 @@ namespace gl
rsx::overlays::resource_config configuration;
configuration.load_files();
for (const auto &res : configuration.texture_raw_data)
for (const auto& res : configuration.texture_raw_data)
{
load_simple_image(res.get(), false, -1);
}
@@ -299,9 +303,9 @@ namespace gl
}
// Create font file
const std::vector<u8> glyph_data = font->get_glyph_data();
const std::vector<u8>& glyph_data = font->get_glyph_data();
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D_ARRAY, font_size.width, font_size.height, font_size.depth, 1, GL_R8);
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D_ARRAY, font_size.width, font_size.height, font_size.depth, 1, 1, GL_R8, RSX_FORMAT_CLASS_COLOR);
tex->copy_from(glyph_data.data(), gl::texture::format::r, gl::texture::type::ubyte, {});
GLenum remap[] = { GL_RED, GL_RED, GL_RED, GL_RED };
@@ -316,11 +320,20 @@ namespace gl
gl::texture_view* ui_overlay_renderer::find_temp_image(rsx::overlays::image_info* desc, u32 owner_uid)
{
auto key = reinterpret_cast<u64>(desc);
//const bool dirty = std::exchange(desc->dirty, false);
const u64 key = reinterpret_cast<u64>(desc);
auto cached = temp_view_cache.find(key);
if (cached != temp_view_cache.end())
{
return cached->second.get();
gl::texture_view* view = cached->second.get();
/*if (dirty)
{
view->image()->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
}*/
return view;
}
return load_simple_image(desc, true, owner_uid);
@@ -350,7 +363,7 @@ namespace gl
}
}
void ui_overlay_renderer::emit_geometry()
void ui_overlay_renderer::emit_geometry(gl::command_context& cmd)
{
if (m_current_primitive_type == rsx::overlays::primitive_type::quad_list)
{
@@ -372,13 +385,19 @@ namespace gl
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
m_vao.bind();
glMultiDrawArrays(GL_TRIANGLE_STRIP, firsts.data(), counts.data(), num_quads);
#ifndef USE_GLES
glMultiDrawArrays(GL_TRIANGLE_STRIP, firsts.data(), counts.data(), num_quads);
#else
for(int n = 0; n < num_quads; ++n){
glDrawArrays(GL_TRIANGLE_STRIP, firsts[n], counts[n]);
}
#endif
glBindVertexArray(old_vao);
}
else
{
overlay_pass::emit_geometry();
overlay_pass::emit_geometry(cmd);
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Emu/system_config_types.h"
#include "Emu/IdManager.h"
#include "util/types.hpp"
#include "../Common/simple_array.hpp"
#include "../Overlays/overlays.h"
@@ -57,7 +58,7 @@ namespace gl
m_vertex_data_buffer.data(elements_count * sizeof(T), data);
}
virtual void emit_geometry();
virtual void emit_geometry(gl::command_context& cmd);
void run(gl::command_context& cmd, const areau& region, GLuint target_texture, GLuint image_aspect_bits, bool enable_blending = false);
};
@@ -87,7 +88,7 @@ namespace gl
void set_primitive_type(rsx::overlays::primitive_type type);
void emit_geometry() override;
void emit_geometry(gl::command_context& cmd) override;
void run(gl::command_context& cmd, const areau& viewport, GLuint target, rsx::overlays::overlay& ui);
};
@@ -112,7 +113,7 @@ namespace gl
template<class T>
T* get_overlay_pass()
{
u32 index = id_manager::typeinfo::get_index<T>();
u32 index = stx::typeindex<id_manager::typeinfo, T>();
auto &e = g_overlay_passes[index];
if (!e)

View File

@@ -1,9 +1,6 @@
#include "stdafx.h"
#include "GLPipelineCompiler.h"
#include "Utilities/Thread.h"
#include <thread>
#include "util/sysinfo.hpp"
namespace gl

View File

@@ -26,7 +26,7 @@ namespace gl
{
const auto target = static_cast<GLenum>(visual->get_target());
const auto ifmt = static_cast<GLenum>(visual->get_internal_format());
g_vis_texture.reset(new texture(target, visual->width(), visual->height(), 1, 1, ifmt, visual->format_class()));
g_vis_texture.reset(new texture(target, visual->width(), visual->height(), 1, 1, 1, ifmt, visual->format_class()));
glCopyImageSubData(visual->id(), target, 0, 0, 0, 0, g_vis_texture->id(), target, 0, 0, 0, 0, visual->width(), visual->height(), 1);
}
}
@@ -115,7 +115,7 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
{
if (!flip_image || flip_image->size2D() != sizeu{ info->width, info->height })
{
flip_image = std::make_unique<gl::texture>(GL_TEXTURE_2D, info->width, info->height, 1, 1, expected_format);
flip_image = std::make_unique<gl::texture>(GL_TEXTURE_2D, info->width, info->height, 1, 1, 1, expected_format, RSX_FORMAT_CLASS_COLOR);
}
};
@@ -382,7 +382,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
}
}
if (g_cfg.video.overlay)
if (g_cfg.video.debug_overlay)
{
const auto num_dirty_textures = m_gl_texture_cache.get_unreleased_textures_count();
const auto texture_memory_size = m_gl_texture_cache.get_texture_memory_in_use() / (1024 * 1024);
@@ -400,8 +400,14 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
const auto vertex_cache_hit_ratio = info.stats.vertex_cache_request_count
? (vertex_cache_hit_count * 100) / info.stats.vertex_cache_request_count
: 0;
const auto program_cache_lookups = info.stats.program_cache_lookups_total;
const auto program_cache_ellided = info.stats.program_cache_lookups_ellided;
const auto program_cache_ellision_rate = program_cache_lookups
? (program_cache_ellided * 100) / program_cache_lookups
: 0;
rsx::overlays::set_debug_overlay_text(fmt::format(
"Internal Resolution: %s\n"
"RSX Load: %3d%%\n"
"draw calls: %16d\n"
"draw call setup: %11dus\n"
@@ -412,12 +418,15 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
"Texture memory: %12dM\n"
"Flush requests: %12d = %2d (%3d%%) hard faults, %2d unavoidable, %2d misprediction(s), %2d speculation(s)\n"
"Texture uploads: %11u (%u from CPU - %02u%%, %u copies avoided)\n"
"Vertex cache hits: %9u/%u (%u%%)",
"Vertex cache hits: %9u/%u (%u%%)\n"
"Program cache lookup ellision: %u/%u (%u%%)",
info.stats.framebuffer_stats.to_string(!backend_config.supports_hw_msaa),
get_load(), info.stats.draw_calls, info.stats.setup_time, info.stats.vertex_upload_time,
info.stats.textures_upload_time, info.stats.draw_exec_time, num_dirty_textures, texture_memory_size,
num_flushes, num_misses, cache_miss_ratio, num_unavoidable, num_mispredict, num_speculate,
num_texture_upload, num_texture_upload_miss, texture_upload_miss_ratio, texture_copies_ellided,
vertex_cache_hit_count, info.stats.vertex_cache_request_count, vertex_cache_hit_ratio)
vertex_cache_hit_count, info.stats.vertex_cache_request_count, vertex_cache_hit_ratio,
program_cache_ellided, program_cache_lookups, program_cache_ellision_rate)
);
}

View File

@@ -183,6 +183,9 @@ OPENGL_PROC(PFNGLUNMAPNAMEDBUFFEREXTPROC, UnmapNamedBufferEXT);
OPENGL_PROC(PFNGLMULTIDRAWELEMENTSPROC, MultiDrawElements);
OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays);
OPENGL_PROC(PFNGLDRAWARRAYSINSTANCEDPROC, DrawArraysInstanced);
OPENGL_PROC(PFNGLDRAWELEMENTSINSTANCEDPROC, DrawElementsInstanced);
OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT);
OPENGL_PROC(PFNGLGETTEXTUREIMAGEPROC, GetTextureImage);
OPENGL_PROC(PFNGLGETTEXTURESUBIMAGEPROC, GetTextureSubImage);
@@ -259,6 +262,13 @@ OPENGL_PROC(PFNGLTEXSTORAGE1DPROC, TexStorage1D);
OPENGL_PROC(PFNGLTEXSTORAGE2DPROC, TexStorage2D);
OPENGL_PROC(PFNGLTEXSTORAGE3DPROC, TexStorage3D);
// ARB_texture_multisample
OPENGL_PROC(PFNGLTEXSTORAGE2DMULTISAMPLEPROC, TexStorage2DMultisample);
OPENGL_PROC(PFNGLTEXSTORAGE3DMULTISAMPLEPROC, TexStorage3DMultisample);
OPENGL_PROC(PFNGLSAMPLEMASKIPROC, SampleMaski);
OPENGL_PROC(PFNGLMINSAMPLESHADINGPROC, MinSampleShading);
OPENGL_PROC(PFNGLSAMPLECOVERAGEPROC, SampleCoverage);
// Texture_View
OPENGL_PROC(PFNGLTEXTUREVIEWPROC, TextureView);

View File

@@ -1,7 +1,6 @@
#pragma once
#include "GLVertexProgram.h"
#include "GLFragmentProgram.h"
#include "GLHelpers.h"
#include "GLPipelineCompiler.h"
#include "../Program/ProgramStateCache.h"
#include "../rsx_utils.h"
@@ -136,13 +135,13 @@ struct GLProgramBuffer : public program_state_cache<GLTraits>
template <typename... Args>
void add_pipeline_entry(const RSXVertexProgram& vp, const RSXFragmentProgram& fp, void* &props, Args&& ...args)
{
get_graphics_pipeline(vp, fp, props, false, false, std::forward<Args>(args)...);
get_graphics_pipeline(nullptr, vp, fp, props, false, false, std::forward<Args>(args)...);
}
void preload_programs(const RSXVertexProgram& vp, const RSXFragmentProgram& fp)
void preload_programs(rsx::program_cache_hint_t* cache_hint, const RSXVertexProgram& vp, const RSXFragmentProgram& fp)
{
search_vertex_program(vp);
search_fragment_program(fp);
search_vertex_program(cache_hint, vp);
search_fragment_program(cache_hint, fp);
}
bool check_cache_missed() const

View File

@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "GLGSRender.h"
#include "GLResolveHelper.h"
#include "Emu/RSX/rsx_methods.h"
#include <span>
@@ -417,15 +418,16 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
}
// Render target helpers
void gl::render_target::clear_memory(gl::command_context& cmd)
void gl::render_target::clear_memory(gl::command_context& cmd, gl::texture* surface)
{
auto dst = surface ? surface : this;
if (aspect() & gl::image_aspect::depth)
{
gl::g_hw_blitter->fast_clear_image(cmd, this, 1.f, 255);
gl::g_hw_blitter->fast_clear_image(cmd, dst, 1.f, 255);
}
else
{
gl::g_hw_blitter->fast_clear_image(cmd, this, {});
gl::g_hw_blitter->fast_clear_image(cmd, dst, {});
}
state_flags &= ~rsx::surface_state_flags::erase_bkgnd;
@@ -449,18 +451,26 @@ void gl::render_target::load_memory(gl::command_context& cmd)
}
else
{
auto tmp = std::make_unique<gl::texture>(GL_TEXTURE_2D, subres.width_in_block, subres.height_in_block, 1, 1, static_cast<GLenum>(get_internal_format()), format_class());
auto tmp = std::make_unique<gl::texture>(GL_TEXTURE_2D, subres.width_in_block, subres.height_in_block, 1, 1, 1, static_cast<GLenum>(get_internal_format()), format_class());
auto dst = samples() > 1 ? get_resolve_target_safe(cmd) : this;
gl::upload_texture(cmd, tmp.get(), get_gcm_format(), is_swizzled, { subres });
gl::g_hw_blitter->scale_image(cmd, tmp.get(), this,
gl::g_hw_blitter->scale_image(cmd, tmp.get(), dst,
{ 0, 0, subres.width_in_block, subres.height_in_block },
{ 0, 0, static_cast<int>(width()), static_cast<int>(height()) },
!is_depth_surface(),
{});
if (samples() > 1)
{
msaa_flags = rsx::surface_state_flags::require_unresolve;
}
}
state_flags &= ~rsx::surface_state_flags::erase_bkgnd;
}
void gl::render_target::initialize_memory(gl::command_context& cmd, rsx::surface_access /*access*/)
void gl::render_target::initialize_memory(gl::command_context& cmd, rsx::surface_access access)
{
const bool memory_load = is_depth_surface() ?
!!g_cfg.video.read_depth_buffer :
@@ -469,6 +479,14 @@ void gl::render_target::initialize_memory(gl::command_context& cmd, rsx::surface
if (!memory_load)
{
clear_memory(cmd);
if (samples() > 1 && access.is_transfer_or_read())
{
// Only clear the resolve surface if reading from it, otherwise it's a waste
clear_memory(cmd, get_resolve_target_safe(cmd));
}
msaa_flags = rsx::surface_state_flags::ready;
}
else
{
@@ -476,8 +494,28 @@ void gl::render_target::initialize_memory(gl::command_context& cmd, rsx::surface
}
}
gl::viewable_image* gl::render_target::get_surface(rsx::surface_access access_type)
{
if (samples() == 1 || !access_type.is_transfer())
{
return this;
}
// A read barrier should have been called before this!
ensure(resolve_surface, "Read access without explicit barrier");
ensure(!(msaa_flags & rsx::surface_state_flags::require_resolve));
return static_cast<gl::viewable_image*>(resolve_surface.get());
}
void gl::render_target::memory_barrier(gl::command_context& cmd, rsx::surface_access access)
{
if (access == rsx::surface_access::gpu_reference)
{
// In OpenGL, resources are always assumed to be visible to the GPU.
// We don't manage memory spilling, so just return.
return;
}
const bool read_access = access.is_read();
const bool is_depth = is_depth_surface();
const bool should_read_buffers = is_depth ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers;
@@ -504,12 +542,33 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, rsx::surface_ac
on_write();
}
if (msaa_flags & rsx::surface_state_flags::require_resolve)
{
if (access.is_transfer())
{
// Only do this step when read access is required
get_resolve_target_safe(cmd);
resolve(cmd);
}
}
else if (msaa_flags & rsx::surface_state_flags::require_unresolve)
{
if (access == rsx::surface_access::shader_write)
{
// Only do this step when it is needed to start rendering
ensure(resolve_surface);
unresolve(cmd);
}
}
return;
}
auto dst_img = (samples() > 1) ? get_resolve_target_safe(cmd) : this;
const bool dst_is_depth = !!(aspect() & gl::image_aspect::depth);
const auto dst_bpp = get_bpp();
unsigned first = prepare_rw_barrier_for_transfer(this);
bool optimize_copy = true;
u64 newest_tag = 0;
for (auto i = first; i < old_contents.size(); ++i)
@@ -519,6 +578,8 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, rsx::surface_ac
const auto src_bpp = src_texture->get_bpp();
rsx::typeless_xfer typeless_info{};
src_texture->memory_barrier(cmd, rsx::surface_access::transfer_read);
if (get_internal_format() == src_texture->get_internal_format())
{
// Copy data from old contents onto this one
@@ -538,29 +599,106 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, rsx::surface_ac
}
section.init_transfer(this);
auto src_area = section.src_rect();
auto dst_area = section.dst_rect();
if (state_flags & rsx::surface_state_flags::erase_bkgnd)
if (g_cfg.video.antialiasing_level != msaa_level::none)
{
const auto area = section.dst_rect();
if (area.x1 > 0 || area.y1 > 0 || unsigned(area.x2) < width() || unsigned(area.y2) < height())
{
initialize_memory(cmd, access);
}
else
{
state_flags &= ~rsx::surface_state_flags::erase_bkgnd;
}
src_texture->transform_pixels_to_samples(src_area);
this->transform_pixels_to_samples(dst_area);
}
gl::g_hw_blitter->scale_image(cmd, section.source, this,
section.src_rect(),
section.dst_rect(),
bool memory_load = true;
if (dst_area.x1 == 0 && dst_area.y1 == 0 &&
unsigned(dst_area.x2) == dst_img->width() && unsigned(dst_area.y2) == dst_img->height())
{
// Skip a bunch of useless work
state_flags &= ~(rsx::surface_state_flags::erase_bkgnd);
msaa_flags = rsx::surface_state_flags::ready;
memory_load = false;
stencil_init_flags = src_texture->stencil_init_flags;
}
else if (state_flags & rsx::surface_state_flags::erase_bkgnd)
{
// Might introduce MSAA flags
initialize_memory(cmd, rsx::surface_access::memory_write);
ensure(state_flags == rsx::surface_state_flags::ready);
}
if (msaa_flags & rsx::surface_state_flags::require_resolve)
{
// Need to forward resolve this
resolve(cmd);
}
if (src_texture->samples() > 1)
{
// Ensure a readable surface exists for the source
src_texture->get_resolve_target_safe(cmd);
}
gl::g_hw_blitter->scale_image(
cmd,
src_texture->get_surface(rsx::surface_access::transfer_read),
this->get_surface(rsx::surface_access::transfer_write),
src_area,
dst_area,
!dst_is_depth, typeless_info);
optimize_copy = optimize_copy && !memory_load;
newest_tag = src_texture->last_use_tag;
}
// Memory has been transferred, discard old contents and update memory flags
// TODO: Preserve memory outside surface clip region
on_write(newest_tag);
if (!newest_tag) [[unlikely]]
{
// Underlying memory has been modified and we could not find valid data to fill it
clear_rw_barrier();
state_flags |= rsx::surface_state_flags::erase_bkgnd;
initialize_memory(cmd, access);
ensure(state_flags == rsx::surface_state_flags::ready);
}
// NOTE: Optimize flag relates to stencil resolve/unresolve for NVIDIA.
on_write_copy(newest_tag, optimize_copy);
if (access == rsx::surface_access::shader_write && samples() > 1)
{
// Write barrier, must initialize
unresolve(cmd);
}
}
// MSAA support
gl::viewable_image* gl::render_target::get_resolve_target_safe(gl::command_context& /*cmd*/)
{
if (!resolve_surface)
{
// Create a resolve surface
const auto resolve_w = width() * samples_x;
const auto resolve_h = height() * samples_y;
resolve_surface.reset(new gl::viewable_image(
GL_TEXTURE_2D,
resolve_w, resolve_h,
1, 1, 1,
static_cast<GLenum>(get_internal_format()),
format_class()
));
}
return static_cast<gl::viewable_image*>(resolve_surface.get());
}
void gl::render_target::resolve(gl::command_context& cmd)
{
gl::resolve_image(cmd, get_resolve_target_safe(cmd), this);
msaa_flags &= ~(rsx::surface_state_flags::require_resolve);
}
void gl::render_target::unresolve(gl::command_context& cmd)
{
gl::unresolve_image(cmd, this, get_resolve_target_safe(cmd));
msaa_flags &= ~(rsx::surface_state_flags::require_unresolve);
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include "../Common/surface_store.h"
#include "GLHelpers.h"
#include "../rsx_utils.h"
#include "glutils/fbo.h"
@@ -49,13 +48,21 @@ namespace gl
{
class render_target : public viewable_image, public rsx::render_target_descriptor<texture*>
{
void clear_memory(gl::command_context& cmd);
void clear_memory(gl::command_context& cmd, gl::texture* surface = nullptr);
void load_memory(gl::command_context& cmd);
void initialize_memory(gl::command_context& cmd, rsx::surface_access access);
// MSAA support:
// Get the linear resolve target bound to this surface. Initialize if none exists
gl::viewable_image* get_resolve_target_safe(gl::command_context& cmd);
// Resolve the planar MSAA data into a linear block
void resolve(gl::command_context& cmd);
// Unresolve the linear data into planar MSAA data
void unresolve(gl::command_context& cmd);
public:
render_target(GLuint width, GLuint height, GLenum sized_format, rsx::format_class format_class)
: viewable_image(GL_TEXTURE_2D, width, height, 1, 1, sized_format, format_class)
render_target(GLuint width, GLuint height, GLubyte samples, GLenum sized_format, rsx::format_class format_class)
: viewable_image(GL_TEXTURE_2D, width, height, 1, 1, samples, sized_format, format_class)
{}
// Internal pitch is the actual row length in bytes of the openGL texture
@@ -81,11 +88,7 @@ namespace gl
return !!(aspect() & gl::image_aspect::depth);
}
viewable_image* get_surface(rsx::surface_access /*access_type*/) override
{
// TODO
return static_cast<gl::viewable_image*>(this);
}
viewable_image* get_surface(rsx::surface_access /*access_type*/) override;
u32 raw_handle() const
{
@@ -141,7 +144,20 @@ struct gl_render_target_traits
auto format = rsx::internals::surface_color_format_to_gl(surface_color_format);
const auto [width_, height_] = rsx::apply_resolution_scale<true>(static_cast<u16>(width), static_cast<u16>(height));
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_,
u8 samples;
rsx::surface_sample_layout sample_layout;
if (g_cfg.video.antialiasing_level == msaa_level::_auto)
{
samples = get_format_sample_count(antialias);
sample_layout = rsx::surface_sample_layout::ps3;
}
else
{
samples = 1;
sample_layout = rsx::surface_sample_layout::null;
}
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_, samples,
static_cast<GLenum>(format.internal_format), RSX_FORMAT_CLASS_COLOR));
result->set_aa_mode(antialias);
@@ -154,6 +170,7 @@ struct gl_render_target_traits
result->memory_usage_flags = rsx::surface_usage_flags::attachment;
result->state_flags = rsx::surface_state_flags::erase_bkgnd;
result->sample_layout = sample_layout;
result->queue_tag(address);
result->add_ref();
return result;
@@ -170,7 +187,20 @@ struct gl_render_target_traits
auto format = rsx::internals::surface_depth_format_to_gl(surface_depth_format);
const auto [width_, height_] = rsx::apply_resolution_scale<true>(static_cast<u16>(width), static_cast<u16>(height));
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_,
u8 samples;
rsx::surface_sample_layout sample_layout;
if (g_cfg.video.antialiasing_level == msaa_level::_auto)
{
samples = get_format_sample_count(antialias);
sample_layout = rsx::surface_sample_layout::ps3;
}
else
{
samples = 1;
sample_layout = rsx::surface_sample_layout::null;
}
std::unique_ptr<gl::render_target> result(new gl::render_target(width_, height_, samples,
static_cast<GLenum>(format.internal_format), rsx::classify_format(surface_depth_format)));
result->set_aa_mode(antialias);
@@ -183,6 +213,7 @@ struct gl_render_target_traits
result->memory_usage_flags = rsx::surface_usage_flags::attachment;
result->state_flags = rsx::surface_state_flags::erase_bkgnd;
result->sample_layout = sample_layout;
result->queue_tag(address);
result->add_ref();
return result;
@@ -200,7 +231,7 @@ struct gl_render_target_traits
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(prev.width, prev.height,
ref->get_surface_width<rsx::surface_metrics::pixels>(), ref->get_surface_height<rsx::surface_metrics::pixels>());
sink = std::make_unique<gl::render_target>(new_w, new_h, internal_format, ref->format_class());
sink = std::make_unique<gl::render_target>(new_w, new_h, ref->samples(), internal_format, ref->format_class());
sink->add_ref();
sink->memory_usage_flags = rsx::surface_usage_flags::storage;
@@ -255,8 +286,9 @@ struct gl_render_target_traits
}
static
void prepare_surface_for_drawing(gl::command_context&, gl::render_target* surface)
void prepare_surface_for_drawing(gl::command_context& cmd, gl::render_target* surface)
{
surface->memory_barrier(cmd, rsx::surface_access::gpu_reference);
surface->memory_usage_flags |= rsx::surface_usage_flags::attachment;
}

View File

@@ -1,6 +1,6 @@
#include "stdafx.h"
#include "GLShaderInterpreter.h"
#include "GLGSRender.h"
#include "GLTextureCache.h"
#include "GLVertexProgram.h"
#include "GLFragmentProgram.h"
#include "../rsx_methods.h"
@@ -46,7 +46,6 @@ namespace gl
void shader_interpreter::create()
{
build_vs();
build_program(::program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES);
build_program(::program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES | ::program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT);
}
@@ -55,14 +54,13 @@ namespace gl
{
for (auto& prog : m_program_cache)
{
prog.second->fs.remove();
prog.second->vertex_shader.remove();
prog.second->fragment_shader.remove();
prog.second->prog.remove();
}
m_vs.remove();
}
glsl::program* shader_interpreter::get(const interpreter::program_metadata& metadata)
glsl::program* shader_interpreter::get(const interpreter::program_metadata& metadata, u32 vp_ctrl, u32 fp_ctrl)
{
// Build options
u64 opt = 0;
@@ -95,13 +93,14 @@ namespace gl
}
}
if (rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_DEPTH_EXPORT;
if (rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT;
if (rsx::method_registers.shader_control() & RSX_SHADER_CONTROL_USES_KIL) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_KIL;
if (fp_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_DEPTH_EXPORT;
if (fp_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_F32_EXPORT;
if (fp_ctrl & RSX_SHADER_CONTROL_USES_KIL) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_KIL;
if (metadata.referenced_textures_mask) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_TEXTURES;
if (metadata.has_branch_instructions) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_FLOW_CTRL;
if (metadata.has_pack_instructions) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_PACKING;
if (rsx::method_registers.polygon_stipple_enabled()) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_STIPPLING;
if (vp_ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS) opt |= program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING;
if (auto it = m_program_cache.find(opt); it != m_program_cache.end()) [[likely]]
{
@@ -115,7 +114,7 @@ namespace gl
return &m_current_interpreter->prog;
}
void shader_interpreter::build_vs()
void shader_interpreter::build_vs(u64 compiler_options, interpreter::cached_program& prog_data)
{
::glsl::shader_properties properties{};
properties.domain = ::glsl::program_domain::glsl_vertex_program;
@@ -126,8 +125,15 @@ namespace gl
RSXVertexProgram null_prog;
std::string shader_str;
ParamArray arr;
null_prog.ctrl = (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING)
? RSX_SHADER_CONTROL_INSTANCED_CONSTANTS
: 0;
GLVertexDecompilerThread comp(null_prog, shader_str, arr);
// Initialize compiler properties
comp.properties.has_indexed_constants = true;
ParamType uniforms = { PF_PARAM_UNIFORM, "vec4" };
uniforms.items.emplace_back("vc[468]", -1);
@@ -141,14 +147,24 @@ namespace gl
// Insert vp stream input
builder << "\n"
"layout(std140, binding = " << GL_INTERPRETER_VERTEX_BLOCK << ") readonly restrict buffer VertexInstructionBlock\n"
"{\n"
" uint base_address;\n"
" uint entry;\n"
" uint output_mask;\n"
" uint control;\n"
" uvec4 vp_instructions[];\n"
"};\n\n";
"layout(std140, binding = " << GL_INTERPRETER_VERTEX_BLOCK << ") readonly restrict buffer VertexInstructionBlock\n"
"{\n"
" uint base_address;\n"
" uint entry;\n"
" uint output_mask;\n"
" uint control;\n"
" uvec4 vp_instructions[];\n"
"};\n\n";
if (compiler_options & program_common::interpreter::COMPILER_OPT_ENABLE_INSTANCING)
{
builder << "#define _ENABLE_INSTANCED_CONSTANTS\n";
}
if (compiler_options)
{
builder << "\n";
}
::glsl::insert_glsl_legacy_function(builder, properties);
::glsl::insert_vertex_input_fetch(builder, ::glsl::glsl_rules::glsl_rules_opengl4);
@@ -156,8 +172,8 @@ namespace gl
builder << program_common::interpreter::get_vertex_interpreter();
const std::string s = builder.str();
m_vs.create(::glsl::program_domain::glsl_vertex_program, s);
m_vs.compile();
prog_data.vertex_shader.create(::glsl::program_domain::glsl_vertex_program, s);
prog_data.vertex_shader.compile();
}
void shader_interpreter::build_fs(u64 compiler_options, interpreter::cached_program& prog_data)
@@ -295,31 +311,32 @@ namespace gl
}
builder <<
"layout(std430, binding =" << GL_INTERPRETER_FRAGMENT_BLOCK << ") readonly restrict buffer FragmentInstructionBlock\n"
"{\n"
" uint shader_control;\n"
" uint texture_control;\n"
" uint reserved1;\n"
" uint reserved2;\n"
" uint texture_handles[16];\n"
" uvec4 fp_instructions[];\n"
"};\n\n";
"layout(std430, binding =" << GL_INTERPRETER_FRAGMENT_BLOCK << ") readonly restrict buffer FragmentInstructionBlock\n"
"{\n"
" uint shader_control;\n"
" uint texture_control;\n"
" uint reserved1;\n"
" uint reserved2;\n"
" uint texture_handles[16];\n"
" uvec4 fp_instructions[];\n"
"};\n\n";
builder << program_common::interpreter::get_fragment_interpreter();
const std::string s = builder.str();
prog_data.fs.create(::glsl::program_domain::glsl_fragment_program, s);
prog_data.fs.compile();
prog_data.fragment_shader.create(::glsl::program_domain::glsl_fragment_program, s);
prog_data.fragment_shader.compile();
}
interpreter::cached_program* shader_interpreter::build_program(u64 compiler_options)
{
auto data = new interpreter::cached_program();
build_fs(compiler_options, *data);
build_vs(compiler_options, *data);
data->prog.create().
attach(m_vs).
attach(data->fs).
attach(data->vertex_shader).
attach(data->fragment_shader).
link();
data->prog.uniforms[0] = GL_STREAM_BUFFER_START + 0;
@@ -347,7 +364,7 @@ namespace gl
return data;
}
bool shader_interpreter::is_interpreter(const glsl::program* program)
bool shader_interpreter::is_interpreter(const glsl::program* program) const
{
return (program == &m_current_interpreter->prog);
}

View File

@@ -1,5 +1,4 @@
#pragma once
#include "GLHelpers.h"
#include "glutils/program.h"
#include "../Program/ProgramStateCache.h"
#include "../Common/TextureUtils.h"
@@ -60,7 +59,8 @@ namespace gl
struct cached_program
{
glsl::shader fs;
glsl::shader vertex_shader;
glsl::shader fragment_shader;
glsl::program prog;
texture_pool_allocator allocator;
};
@@ -68,10 +68,10 @@ namespace gl
class shader_interpreter
{
glsl::shader m_vs;
std::unordered_map<u64, std::unique_ptr<interpreter::cached_program>> m_program_cache;
using shader_cache_t = std::unordered_map<u64, std::unique_ptr<interpreter::cached_program>>;
shader_cache_t m_program_cache;
void build_vs();
void build_vs(u64 compiler_options, interpreter::cached_program& prog_data);
void build_fs(u64 compiler_options, interpreter::cached_program& prog_data);
interpreter::cached_program* build_program(u64 compiler_options);
@@ -83,7 +83,7 @@ namespace gl
void update_fragment_textures(const std::array<std::unique_ptr<rsx::sampled_image_descriptor_base>, 16>& descriptors, u16 reference_mask, u32* out);
glsl::program* get(const interpreter::program_metadata& fp_metadata);
bool is_interpreter(const glsl::program* program);
glsl::program* get(const interpreter::program_metadata& fp_metadata, u32 vp_ctrl, u32 fp_ctrl);
bool is_interpreter(const glsl::program* program) const;
};
}

View File

@@ -1,16 +1,13 @@
#include "stdafx.h"
#include "GLTexture.h"
#include "GLCompute.h"
#include "GLRenderTargets.h"
#include "GLOverlays.h"
#include "GLGSRender.h"
#include "glutils/blitter.h"
#include "glutils/ring_buffer.h"
#include "../GCM.h"
#include "../RSXThread.h"
#include "../RSXTexture.h"
#include "util/asm.hpp"
@@ -73,6 +70,7 @@ namespace gl
GLenum get_sized_internal_format(u32 texture_format)
{
const bool supports_dxt = get_driver_caps().EXT_texture_compression_s3tc_supported;
switch (texture_format)
{
case CELL_GCM_TEXTURE_B8: return GL_R8;
@@ -95,9 +93,9 @@ namespace gl
case CELL_GCM_TEXTURE_D1R5G5B5: return GL_BGR5_A1;
case CELL_GCM_TEXTURE_D8R8G8B8: return GL_BGRA8;
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return GL_RG16F;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_BGRA8;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : GL_BGRA8;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_BGRA8;
case CELL_GCM_TEXTURE_COMPRESSED_HILO8: return GL_RG8;
case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: return GL_RG8_SNORM;
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: return GL_BGRA8;
@@ -108,6 +106,7 @@ namespace gl
std::tuple<GLenum, GLenum> get_format_type(u32 texture_format)
{
const bool supports_dxt = get_driver_caps().EXT_texture_compression_s3tc_supported;
switch (texture_format)
{
case CELL_GCM_TEXTURE_B8: return std::make_tuple(GL_RED, GL_UNSIGNED_BYTE);
@@ -130,9 +129,9 @@ namespace gl
case CELL_GCM_TEXTURE_D1R5G5B5: return std::make_tuple(GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV);
case CELL_GCM_TEXTURE_D8R8G8B8: return std::make_tuple(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV);
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: return std::make_tuple(GL_RG, GL_HALF_FLOAT);
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return std::make_tuple(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return std::make_tuple(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return std::make_tuple(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: return std::make_tuple(supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_BGRA, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: return std::make_tuple(supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : GL_BGRA, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return std::make_tuple(supports_dxt ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_BGRA, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_HILO8: return std::make_tuple(GL_RG, GL_UNSIGNED_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: return std::make_tuple(GL_RG, GL_BYTE);
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: return std::make_tuple(GL_BGRA, GL_UNSIGNED_BYTE);
@@ -429,7 +428,7 @@ namespace gl
image_region.height *= dst_region.depth;
scratch = std::make_unique<gl::texture>(
GL_TEXTURE_2D,
image_region.x + image_region.width, image_region.y + image_region.height, 1, 1,
image_region.x + image_region.width, image_region.y + image_region.height, 1, 1, 1,
static_cast<GLenum>(dst->get_internal_format()), dst->format_class());
scratch_view = std::make_unique<gl::nil_texture_view>(scratch.get());
@@ -445,7 +444,7 @@ namespace gl
{
scratch = std::make_unique<gl::texture>(
GL_TEXTURE_2D,
image_region.x + image_region.width, 1, 1, 1,
image_region.x + image_region.width, 1, 1, 1, 1,
static_cast<GLenum>(dst->get_internal_format()), dst->format_class());
scratch_view = std::make_unique<gl::nil_texture_view>(scratch.get());
@@ -576,20 +575,21 @@ namespace gl
const GLenum internal_format = get_sized_internal_format(gcm_format);
const auto format_class = rsx::classify_format(gcm_format);
return new gl::viewable_image(target, width, height, depth, mipmaps, internal_format, format_class);
return new gl::viewable_image(target, width, height, depth, mipmaps, 1, internal_format, format_class);
}
void fill_texture(gl::command_context& cmd, texture* dst, int format,
const std::vector<rsx::subresource_layout> &input_layouts,
bool is_swizzled, GLenum gl_format, GLenum gl_type, rsx::simple_array<std::byte>& staging_buffer)
{
const auto driver_caps = gl::get_driver_caps();
const auto& driver_caps = gl::get_driver_caps();
rsx::texture_uploader_capabilities caps
{
.supports_byteswap = true,
.supports_vtc_decoding = false,
.supports_hw_deswizzle = driver_caps.ARB_compute_shader_supported,
.supports_zero_copy = false,
.supports_dxt = driver_caps.EXT_texture_compression_s3tc_supported,
.alignment = 4
};
@@ -599,7 +599,7 @@ namespace gl
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
if (rsx::is_compressed_host_format(format)) [[likely]]
if (rsx::is_compressed_host_format(caps, format)) [[likely]]
{
caps.supports_vtc_decoding = driver_caps.vendor_NVIDIA;
unpack_settings.apply();
@@ -631,7 +631,7 @@ namespace gl
{
const GLsizei size = layout.width_in_block * layout.height_in_block * format_block_size;
ensure(usz(size) <= staging_buffer.size());
if (gl::get_driver_caps().ARB_dsa_supported)
if (gl::get_driver_caps().ARB_direct_state_access_supported)
{
glCompressedTextureSubImage3D(dst->id(), layout.level, 0, 0, layout.layer, layout.width_in_texel, layout.height_in_texel, 1, gl_format, size, staging_buffer.data());
}
@@ -690,13 +690,13 @@ namespace gl
if (driver_caps.ARB_compute_shader_supported)
{
u64 row_pitch = rsx::align2<u64, u64>(layout.width_in_block * block_size_in_bytes, caps.alignment);
if (!rsx::is_compressed_host_format(format))
{
// Handle emulated compressed formats with host unpack (R8G8 compressed)
row_pitch = std::max<u64>(row_pitch, dst->pitch());
}
image_linear_size = row_pitch * layout.height_in_block * layout.depth;
// We're in the "else" branch, so "is_compressed_host_format()" is always false.
// Handle emulated compressed formats with host unpack (R8G8 compressed)
row_pitch = std::max<u64>(row_pitch, dst->pitch());
// FIXME: Double-check this logic; it seems like we should always use texels both here and for row_pitch.
image_linear_size = row_pitch * layout.height_in_texel * layout.depth;
compute_scratch_mem = { nullptr, g_compute_decode_buffer.alloc(static_cast<u32>(image_linear_size), 256) };
compute_scratch_mem.first = reinterpret_cast<void*>(static_cast<uintptr_t>(compute_scratch_mem.second));
@@ -818,7 +818,8 @@ namespace gl
// Calculate staging buffer size
rsx::simple_array<std::byte> data_upload_buf;
if (rsx::is_compressed_host_format(gcm_format))
rsx::texture_uploader_capabilities caps { .supports_dxt = gl::get_driver_caps().EXT_texture_compression_s3tc_supported };
if (rsx::is_compressed_host_format(caps, gcm_format))
{
const auto& desc = subresources_layout[0];
const u32 texture_data_sz = desc.width_in_block * desc.height_in_block * desc.depth * rsx::get_format_block_size_in_bytes(gcm_format);

View File

@@ -1,12 +1,9 @@
#pragma once
#include "OpenGL.h"
#include "../GCM.h"
#include "../Common/TextureUtils.h"
#include "GLHelpers.h"
#include <unordered_map>
namespace rsx
{
class vertex_texture;

View File

@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Emu/RSX/RSXThread.h"
#include "GLTexture.h"
#include "GLTextureCache.h"
#include "../Common/BufferUtils.h"
@@ -149,7 +148,7 @@ namespace gl
if (!dst)
{
std::unique_ptr<temporary_image_t> data = std::make_unique<temporary_image_t>(dst_target, width, height, depth, mipmaps, sized_internal_fmt, rsx::classify_format(gcm_format));
std::unique_ptr<temporary_image_t> data = std::make_unique<temporary_image_t>(dst_target, width, height, depth, mipmaps, 1, sized_internal_fmt, rsx::classify_format(gcm_format));
dst = data.get();
dst->properties_encoding = match_key;
m_temporary_surfaces.emplace_back(std::move(data));
@@ -223,7 +222,12 @@ namespace gl
{
const auto src_bpp = slice.src->pitch() / slice.src->width();
const u16 convert_w = u16(slice.src->width() * src_bpp) / dst_bpp;
tmp = std::make_unique<texture>(GL_TEXTURE_2D, convert_w, slice.src->height(), 1, 1, static_cast<GLenum>(dst_image->get_internal_format()), dst_image->format_class());
tmp = std::make_unique<texture>(
GL_TEXTURE_2D,
convert_w, slice.src->height(),
1, 1, 1,
static_cast<GLenum>(dst_image->get_internal_format()),
dst_image->format_class());
src_image = tmp.get();
@@ -264,9 +268,17 @@ namespace gl
const areai dst_rect = { slice.dst_x, slice.dst_y, slice.dst_x + slice.dst_w, slice.dst_y + slice.dst_h };
gl::texture* _dst = dst_image;
if (src_image->get_internal_format() != dst_image->get_internal_format() || slice.level != 0 || slice.dst_z != 0) [[ unlikely ]]
if (src_image->get_internal_format() != dst_image->get_internal_format() ||
slice.level != 0 ||
slice.dst_z != 0) [[ unlikely ]]
{
tmp = std::make_unique<texture>(GL_TEXTURE_2D, dst_rect.x2, dst_rect.y2, 1, 1, static_cast<GLenum>(slice.src->get_internal_format()));
tmp = std::make_unique<texture>(
GL_TEXTURE_2D,
dst_rect.x2, dst_rect.y2,
1, 1, 1,
static_cast<GLenum>(slice.src->get_internal_format()),
slice.src->format_class());
_dst = tmp.get();
}

View File

@@ -69,7 +69,10 @@ namespace gl
void create(u16 w, u16 h, u16 depth, u16 mipmaps, gl::texture* image, u32 rsx_pitch, bool managed,
gl::texture::format gl_format = gl::texture::format::rgba, gl::texture::type gl_type = gl::texture::type::ubyte, bool swap_bytes = false)
{
if (vram_texture && !managed_texture && get_protection() == utils::protection::no)
auto new_texture = static_cast<gl::viewable_image*>(image);
ensure(!exists() || !is_managed() || vram_texture == new_texture);
if (vram_texture != new_texture && !managed_texture && get_protection() == utils::protection::no)
{
// In-place image swap, still locked. Likely a color buffer that got rebound as depth buffer or vice-versa.
gl::as_rtt(vram_texture)->on_swap_out();
@@ -81,8 +84,6 @@ namespace gl
}
}
auto new_texture = static_cast<gl::viewable_image*>(image);
ensure(!exists() || !is_managed() || vram_texture == new_texture);
vram_texture = new_texture;
if (managed)
@@ -262,28 +263,24 @@ namespace gl
baseclass::on_miss();
}
gl::texture* target_texture = vram_texture;
u32 transfer_width = width;
u32 transfer_height = height;
if (context == rsx::texture_upload_context::framebuffer_storage)
{
auto as_rtt = static_cast<gl::render_target*>(vram_texture);
if (as_rtt->dirty()) as_rtt->read_barrier(cmd);
auto surface = gl::as_rtt(vram_texture);
surface->memory_barrier(cmd, rsx::surface_access::transfer_read);
target_texture = surface->get_surface(rsx::surface_access::transfer_read);
transfer_width *= surface->samples_x;
transfer_height *= surface->samples_y;
}
gl::texture* target_texture = vram_texture;
if ((rsx::get_resolution_scale_percent() != 100 && context == rsx::texture_upload_context::framebuffer_storage) ||
(vram_texture->pitch() != rsx_pitch))
{
u32 real_width = width;
u32 real_height = height;
if (context == rsx::texture_upload_context::framebuffer_storage)
{
auto surface = gl::as_rtt(vram_texture);
real_width *= surface->samples_x;
real_height *= surface->samples_y;
}
areai src_area = { 0, 0, 0, 0 };
const areai dst_area = { 0, 0, static_cast<s32>(real_width), static_cast<s32>(real_height) };
const areai dst_area = { 0, 0, static_cast<s32>(transfer_width), static_cast<s32>(transfer_height) };
auto ifmt = vram_texture->get_internal_format();
src_area.x2 = vram_texture->width();
@@ -294,22 +291,22 @@ namespace gl
if (scaled_texture)
{
auto sfmt = scaled_texture->get_internal_format();
if (scaled_texture->width() != real_width ||
scaled_texture->height() != real_height ||
if (scaled_texture->width() != transfer_width ||
scaled_texture->height() != transfer_height ||
sfmt != ifmt)
{
//Discard current scaled texture
// Discard current scaled texture
scaled_texture.reset();
}
}
if (!scaled_texture)
{
scaled_texture = std::make_unique<gl::texture>(GL_TEXTURE_2D, real_width, real_height, 1, 1, static_cast<GLenum>(ifmt));
scaled_texture = std::make_unique<gl::texture>(GL_TEXTURE_2D, transfer_width, transfer_height, 1, 1, 1, static_cast<GLenum>(ifmt), vram_texture->format_class());
}
const bool linear_interp = is_depth_texture() ? false : true;
g_hw_blitter->scale_image(cmd, vram_texture, scaled_texture.get(), src_area, dst_area, linear_interp, {});
g_hw_blitter->scale_image(cmd, target_texture, scaled_texture.get(), src_area, dst_area, linear_interp, {});
target_texture = scaled_texture.get();
}
}

View File

@@ -153,7 +153,7 @@ gl::vertex_upload_info GLGSRender::set_vertex_buffer()
m_profiler.start();
//Write index buffers and count verts
auto result = std::visit(draw_command_visitor(*m_index_ring_buffer, m_vertex_layout), get_draw_command(rsx::method_registers));
auto result = std::visit(draw_command_visitor(*m_index_ring_buffer, m_vertex_layout), m_draw_processor.get_draw_command(rsx::method_registers));
const u32 vertex_count = (result.max_index - result.min_index) + 1;
u32 vertex_base = result.min_index;
@@ -250,7 +250,7 @@ gl::vertex_upload_info GLGSRender::set_vertex_buffer()
}
//Write all the data
write_vertex_data_to_memory(m_vertex_layout, vertex_base, vertex_count, persistent_mapping.first, volatile_mapping.first);
m_draw_processor.write_vertex_data_to_memory(m_vertex_layout, vertex_base, vertex_count, persistent_mapping.first, volatile_mapping.first);
m_frame_stats.vertex_upload_time += m_profiler.duration();
return upload_info;

View File

@@ -1,14 +1,11 @@
#include "stdafx.h"
#include "GLVertexProgram.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "GLCommonDecompiler.h"
#include "../Program/GLSLCommon.h"
#include <algorithm>
std::string GLVertexDecompilerThread::getFloatTypeName(usz elementCount)
{
return glsl::getFloatTypeNameImpl(elementCount);
@@ -31,30 +28,31 @@ std::string GLVertexDecompilerThread::compareFunction(COMPARE f, const std::stri
void GLVertexDecompilerThread::insertHeader(std::stringstream &OS)
{
OS << "#version 430\n";
OS << "layout(std140, binding = " << GL_VERTEX_PARAMS_BIND_SLOT << ") uniform VertexContextBuffer\n";
OS << "{\n";
OS << " mat4 scale_offset_mat;\n";
OS << " ivec4 user_clip_enabled[2];\n";
OS << " vec4 user_clip_factor[2];\n";
OS << " uint transform_branch_bits;\n";
OS << " float point_size;\n";
OS << " float z_near;\n";
OS << " float z_far;\n";
OS << "};\n\n";
OS <<
"#version 430\n"
"layout(std140, binding = " << GL_VERTEX_PARAMS_BIND_SLOT << ") uniform VertexContextBuffer\n"
"{\n"
" mat4 scale_offset_mat;\n"
" ivec4 user_clip_enabled[2];\n"
" vec4 user_clip_factor[2];\n"
" uint transform_branch_bits;\n"
" float point_size;\n"
" float z_near;\n"
" float z_far;\n"
"};\n\n"
OS << "layout(std140, binding = " << GL_VERTEX_LAYOUT_BIND_SLOT << ") uniform VertexLayoutBuffer\n";
OS << "{\n";
OS << " uint vertex_base_index;\n";
OS << " uint vertex_index_offset;\n";
OS << " uvec4 input_attributes_blob[16 / 2];\n";
OS << "};\n\n";
"layout(std140, binding = " << GL_VERTEX_LAYOUT_BIND_SLOT << ") uniform VertexLayoutBuffer\n"
"{\n"
" uint vertex_base_index;\n"
" uint vertex_index_offset;\n"
" uvec4 input_attributes_blob[16 / 2];\n"
"};\n\n";
}
void GLVertexDecompilerThread::insertInputs(std::stringstream& OS, const std::vector<ParamType>& /*inputs*/)
{
OS << "layout(location=0) uniform usamplerBuffer persistent_input_stream;\n"; //Data stream with persistent vertex data (cacheable)
OS << "layout(location=1) uniform usamplerBuffer volatile_input_stream;\n"; //Data stream with per-draw data (registers and immediate draw data)
OS << "layout(location=0) uniform usamplerBuffer persistent_input_stream;\n"; // Data stream with persistent vertex data (cacheable)
OS << "layout(location=1) uniform usamplerBuffer volatile_input_stream;\n"; // Data stream with per-draw data (registers and immediate draw data)
}
void GLVertexDecompilerThread::insertConstants(std::stringstream& OS, const std::vector<ParamType>& constants)
@@ -65,15 +63,58 @@ void GLVertexDecompilerThread::insertConstants(std::stringstream& OS, const std:
{
if (PI.name.starts_with("vc["))
{
OS << "layout(std140, binding = " << GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT << ") uniform VertexConstantsBuffer\n";
OS << "{\n";
OS << " vec4 " << PI.name << ";\n";
OS << "};\n\n";
if (!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS))
{
OS <<
"layout(std140, binding = " << GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT << ") uniform VertexConstantsBuffer\n"
"{\n"
" vec4 " << PI.name << ";\n"
"};\n\n";
}
else
{
OS <<
"layout(std430, binding = " << GL_INSTANCING_LUT_BIND_SLOT << ") readonly buffer InstancingIndirectionLUT\n"
"{\n"
" int constants_addressing_lookup[];\n"
"};\n\n"
"layout(std430, binding = " << GL_INSTANCING_XFORM_CONSTANTS_SLOT << ") readonly buffer InstancingVertexConstantsBlock\n"
"{\n"
" vec4 instanced_constants_array[];\n"
"};\n\n"
"#define CONSTANTS_ARRAY_LENGTH " << (properties.has_indexed_constants ? 468 : ::size32(m_constant_ids)) << "\n\n";
}
continue;
}
OS << "uniform " << PT.type << " " << PI.name << ";\n";
auto type = PT.type;
if (PT.type == "sampler2D" ||
PT.type == "samplerCube" ||
PT.type == "sampler1D" ||
PT.type == "sampler3D")
{
if (m_prog.texture_state.multisampled_textures) [[ unlikely ]]
{
ensure(PI.name.length() > 3);
int index = atoi(&PI.name[3]);
if (m_prog.texture_state.multisampled_textures & (1 << index))
{
if (type != "sampler1D" && type != "sampler2D")
{
rsx_log.error("Unexpected multisampled sampler type '%s'", type);
}
type = "sampler2DMS";
}
}
}
OS << "uniform " << type << " " << PI.name << ";\n";
}
}
}
@@ -83,12 +124,12 @@ static const vertex_reg_info reg_table[] =
{ "gl_Position", false, "dst_reg0", "", false },
{ "diff_color", true, "dst_reg1", "", false, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE },
{ "spec_color", true, "dst_reg2", "", false, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR },
//These are only present when back variants are specified, otherwise the default diff/spec color vars are for both front and back
// These are only present when back variants are specified, otherwise the default diff/spec color vars are for both front and back
{ "diff_color1", true, "dst_reg3", "", false, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE },
{ "spec_color1", true, "dst_reg4", "", false, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR },
//Fog output shares a data source register with clip planes 0-2 so only declare when specified
// Fog output shares a data source register with clip planes 0-2 so only declare when specified
{ "fog_c", true, "dst_reg5", ".xxxx", true, "", "", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_FOG },
//Warning: Always define all 3 clip plane groups together to avoid flickering with openGL
// Warning: Always define all 3 clip plane groups together to avoid flickering with openGL
{ "gl_ClipDistance[0]", false, "dst_reg5", ".y * user_clip_factor[0].x", false, "user_clip_enabled[0].x > 0", "0.5", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_UC0 },
{ "gl_ClipDistance[1]", false, "dst_reg5", ".z * user_clip_factor[0].y", false, "user_clip_enabled[0].y > 0", "0.5", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_UC1 },
{ "gl_ClipDistance[2]", false, "dst_reg5", ".w * user_clip_factor[0].z", false, "user_clip_enabled[0].z > 0", "0.5", "", true, CELL_GCM_ATTRIB_OUTPUT_MASK_UC2 },
@@ -131,6 +172,7 @@ void GLVertexDecompilerThread::insertMainStart(std::stringstream & OS)
properties2.emulate_depth_clip_only = dev_caps.NV_depth_buffer_float_supported;
properties2.low_precision_tests = dev_caps.vendor_NVIDIA;
properties2.require_explicit_invariance = dev_caps.vendor_MESA || (dev_caps.vendor_NVIDIA && g_cfg.video.shader_precision != gpu_preset_level::low);
properties2.require_instanced_render = !!(m_prog.ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS);
insert_glsl_legacy_function(OS, properties2);
glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_opengl4, dev_caps.vendor_INTEL == false);
@@ -167,7 +209,7 @@ void GLVertexDecompilerThread::insertMainStart(std::stringstream & OS)
OS << "void vs_main()\n";
OS << "{\n";
//Declare temporary registers, ignoring those mapped to outputs
// Declare temporary registers, ignoring those mapped to outputs
for (const ParamType &PT : m_parr.params[PF_PARAM_NONE])
{
for (const ParamItem &PI : PT.items)
@@ -216,7 +258,7 @@ void GLVertexDecompilerThread::insertMainEnd(std::stringstream & OS)
}
else
{
//Insert if-else condition
// Insert if-else condition
OS << " " << i.name << " = " << condition << "? " << i.src_reg << i.src_reg_mask << ": " << i.default_val << ";\n";
}
@@ -240,21 +282,21 @@ void GLVertexDecompilerThread::insertMainEnd(std::stringstream & OS)
OS << " gl_Position = gl_Position * scale_offset_mat;\n";
OS << " gl_Position = apply_zclip_xform(gl_Position, z_near, z_far);\n";
//Since our clip_space is symmetrical [-1, 1] we map it to linear space using the eqn:
//ln = (clip * 2) - 1 to fully utilize the 0-1 range of the depth buffer
//RSX matrices passed already map to the [0, 1] range but mapping to classic OGL requires that we undo this step
//This can be made unnecessary using the call glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE).
//However, ClipControl only made it to opengl core in ver 4.5 though, so this is a workaround.
//NOTE: It is completely valid for games to use very large w values, causing the post-multiplied z to be in the hundreds
//It is therefore critical that this step is done post-transform and the result re-scaled by w
//SEE Naruto: UNS
//NOTE: On GPUs, poor fp32 precision means dividing z by w, then multiplying by w again gives slightly incorrect results
//This equation is simplified algebraically to an addition and subtraction which gives more accurate results (Fixes flickering skybox in Dark Souls 2)
//OS << " float ndc_z = gl_Position.z / gl_Position.w;\n";
//OS << " ndc_z = (ndc_z * 2.) - 1.;\n";
//OS << " gl_Position.z = ndc_z * gl_Position.w;\n";
// Since our clip_space is symmetrical [-1, 1] we map it to linear space using the eqn:
// ln = (clip * 2) - 1 to fully utilize the 0-1 range of the depth buffer
// RSX matrices passed already map to the [0, 1] range but mapping to classic OGL requires that we undo this step
// This can be made unnecessary using the call glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE).
// However, ClipControl only made it to opengl core in ver 4.5 though, so this is a workaround.
// NOTE: It is completely valid for games to use very large w values, causing the post-multiplied z to be in the hundreds
// It is therefore critical that this step is done post-transform and the result re-scaled by w
// SEE Naruto: UNS
// NOTE: On GPUs, poor fp32 precision means dividing z by w, then multiplying by w again gives slightly incorrect results
// This equation is simplified algebraically to an addition and subtraction which gives more accurate results (Fixes flickering skybox in Dark Souls 2)
// OS << " float ndc_z = gl_Position.z / gl_Position.w;\n";
// OS << " ndc_z = (ndc_z * 2.) - 1.;\n";
// OS << " gl_Position.z = ndc_z * gl_Position.w;\n";
OS << " gl_Position.z = (gl_Position.z + gl_Position.z) - gl_Position.w;\n";
OS << "}\n";
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include "../Program/VertexProgramDecompiler.h"
#include "GLHelpers.h"
#include "glutils/program.h"
#include <unordered_map>

View File

@@ -36,12 +36,10 @@ void gl::init()
#undef OPENGL_PROC2
#endif
#ifdef __unix__
#ifndef __ANDROID__
glewExperimental = true;
glewInit();
#endif
#ifdef HAVE_X11
glxewInit();
#endif
@@ -53,11 +51,10 @@ void gl::set_swapinterval(int interval)
#ifdef _WIN32
wglSwapIntervalEXT(interval);
#elif defined(__ANDROID__)
if (auto egl_display = eglGetCurrentDisplay(); egl_display != EGL_NO_DISPLAY)
{
eglSwapInterval(egl_display, interval);
return;
}
if (auto egl_display = eglGetCurrentDisplay(); egl_display != EGL_NO_DISPLAY)
{
eglSwapInterval(egl_display, interval);
}
#elif defined(HAVE_X11)
if (glXSwapIntervalEXT)
{
@@ -68,7 +65,7 @@ if (auto egl_display = eglGetCurrentDisplay(); egl_display != EGL_NO_DISPLAY)
}
}
#if defined(HAVE_WAYLAND)
#ifdef HAVE_WAYLAND
if (auto egl_display = eglGetCurrentDisplay(); egl_display != EGL_NO_DISPLAY)
{
eglSwapInterval(egl_display, interval);

View File

@@ -1,9 +1,9 @@
#pragma once
#if defined(_WIN32)||defined(__ANDROID__)
//
#else
#ifndef _WIN32
#ifndef __ANDROID__
#include <GL/glew.h>
#endif
#endif
#ifdef _WIN32
#include <Windows.h>
@@ -23,7 +23,31 @@ typedef BOOL (WINAPI* PFNWGLSWAPINTERVALEXTPROC) (int interval);
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#elif defined(__ANDROID__)
#include <GLES3/gl3.h>
#include <GLES3/gl32.h>
#define USE_GLES
#define _GL_DOUBLE 0x140A
#define _GL_UNSIGNED_BYTE_3_3_2 0x8032
#define _GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
#define _GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
#define _GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
#define _GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
#define _GL_UNSIGNED_INT_8_8_8_8 0x8035
#define _GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#define _GL_UNSIGNED_INT_10_10_10_2 0x8036
#define _GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define _GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define _GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define _GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#define _GL_R16 0x822A
#define _GL_RG16 0x822C
#define _GL_MIRROR_CLAMP_EXT 0x8742
//#define _GL_MIRROR_CLAMP_TO_EDGE 0x8743
#define _GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912
#define _GL_BGR 0x80E0
#define _GL_BGRA 0x80E1
#define _GL_TEXTURE_1D 0x0DE0
#else
#include <GL/gl.h>
#ifdef HAVE_X11

View File

@@ -3,7 +3,6 @@
#include "state_tracker.hpp"
#include "../GLTexture.h" // TODO: This system also needs to be refactored
#include "../GLOverlays.h"
namespace gl
{
@@ -67,7 +66,7 @@ namespace gl
if (static_cast<gl::texture::internal_format>(internal_fmt) != src->get_internal_format())
{
const u16 internal_width = static_cast<u16>(src->width() * xfer_info.src_scaling_hint);
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, 1, internal_fmt, RSX_FORMAT_CLASS_DONT_CARE);
copy_typeless(cmd, typeless_src.get(), src);
real_src = typeless_src.get();
@@ -85,7 +84,7 @@ namespace gl
if (static_cast<gl::texture::internal_format>(internal_fmt) != dst->get_internal_format())
{
const auto internal_width = static_cast<u16>(dst->width() * xfer_info.dst_scaling_hint);
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, 1, internal_fmt, RSX_FORMAT_CLASS_DONT_CARE);
copy_typeless(cmd, typeless_dst.get(), dst);
real_dst = typeless_dst.get();

View File

@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "buffer_object.h"
#include "common.h"
namespace gl
{
@@ -7,6 +8,7 @@ namespace gl
{
m_memory_type = type;
#ifndef USE_GLES
if (const auto& caps = get_driver_caps();
type != memory_type::userptr && caps.ARB_buffer_storage_supported)
{
@@ -47,6 +49,7 @@ namespace gl
m_size = size;
}
else
#endif
{
data(size, data_, GL_STREAM_COPY);
}
@@ -114,6 +117,10 @@ namespace gl
m_size = size;
#ifdef USE_GLES
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBufferData(GL_ARRAY_BUFFER, size, data_, usage);
#else
if (m_memory_type == memory_type::userptr)
{
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_id);
@@ -122,12 +129,19 @@ namespace gl
}
DSA_CALL2(NamedBufferData, m_id, size, data_, usage);
#endif
}
void buffer::sub_data(GLsizeiptr offset, GLsizeiptr length, const GLvoid* data)
{
ensure(m_memory_type == memory_type::local);
#ifdef USE_GLES
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBufferSubData(GL_ARRAY_BUFFER, offset,length, data);
#else
DSA_CALL2(NamedBufferSubData, m_id, offset, length, data);
#endif
}
GLubyte* buffer::map(GLsizeiptr offset, GLsizeiptr length, access access_)
@@ -137,14 +151,24 @@ namespace gl
GLenum access_bits = static_cast<GLenum>(access_);
if (access_bits == GL_MAP_WRITE_BIT) access_bits |= GL_MAP_UNSYNCHRONIZED_BIT;
#ifdef USE_GLES
glBindBuffer(GL_ARRAY_BUFFER, m_id);
auto raw_data=glMapBufferRange(GL_ARRAY_BUFFER, offset,length, access_bits);
#else
auto raw_data = DSA_CALL2_RET(MapNamedBufferRange, id(), offset, length, access_bits);
#endif
return reinterpret_cast<GLubyte*>(raw_data);
}
void buffer::unmap()
{
ensure(m_memory_type == memory_type::host_visible);
#ifdef USE_GLES
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glUnmapBuffer(GL_ARRAY_BUFFER);
#else
DSA_CALL2(UnmapNamedBuffer, id());
#endif
}
void buffer::bind_range(u32 index, u32 offset, u32 size) const
@@ -161,7 +185,13 @@ namespace gl
void buffer::copy_to(buffer* other, u64 src_offset, u64 dst_offset, u64 size)
{
if (get_driver_caps().ARB_dsa_supported)
#ifdef USE_GLES
glBindBuffer(GL_COPY_READ_BUFFER, this->id());
glBindBuffer(GL_COPY_WRITE_BUFFER, other->id());
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, src_offset, dst_offset, size);
#else
if (get_driver_caps().ARB_direct_state_access_supported)
{
glCopyNamedBufferSubData(this->id(), other->id(), src_offset, dst_offset, size);
}
@@ -169,6 +199,7 @@ namespace gl
{
glNamedCopyBufferSubDataEXT(this->id(), other->id(), src_offset, dst_offset, size);
}
#endif
}
// Buffer view

View File

@@ -1,6 +1,6 @@
#pragma once
#include "common.h"
#include "Emu/RSX/GL/OpenGL.h"
namespace gl
{
@@ -23,7 +23,9 @@ namespace gl
read = GL_MAP_READ_BIT,
write = GL_MAP_WRITE_BIT,
rw = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
#ifndef USE_GLES
persistent_rw = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT
#endif
};
enum class memory_type

View File

@@ -3,6 +3,8 @@
#include "Utilities/StrUtil.h"
#include <unordered_set>
namespace gl
{
version_info::version_info(const char* version_string, int major_scale)
@@ -20,20 +22,8 @@ namespace gl
version = static_cast<u16>(version_major * major_scale) + version_minor;
}
bool capabilities::check(const std::string& ext_name, const char* test)
{
if (ext_name == test)
{
rsx_log.notice("Extension %s is supported", ext_name);
return true;
}
return false;
}
void capabilities::initialize()
{
int find_count = 17;
int ext_count = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_count);
@@ -47,132 +37,61 @@ namespace gl
std::string version_string = reinterpret_cast<const char*>(glGetString(GL_VERSION));
std::string renderer_string = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
std::unordered_set<std::string> all_extensions;
for (int i = 0; i < ext_count; i++)
{
if (!find_count) break;
const std::string ext_name = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
if (check(ext_name, "GL_ARB_shader_draw_parameters"))
{
ARB_shader_draw_parameters_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_EXT_direct_state_access"))
{
EXT_dsa_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_direct_state_access"))
{
ARB_dsa_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_bindless_texture"))
{
ARB_bindless_texture_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_buffer_storage"))
{
ARB_buffer_storage_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_texture_buffer_object"))
{
ARB_texture_buffer_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_depth_buffer_float"))
{
ARB_depth_buffer_float_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_texture_barrier"))
{
ARB_texture_barrier_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_NV_texture_barrier"))
{
NV_texture_barrier_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_NV_gpu_shader5"))
{
NV_gpu_shader5_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_AMD_gpu_shader_half_float"))
{
AMD_gpu_shader_half_float_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_compute_shader"))
{
ARB_compute_shader_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_EXT_depth_bounds_test"))
{
EXT_depth_bounds_test = true;
find_count--;
continue;
}
if (check(ext_name, "GL_NV_depth_buffer_float"))
{
NV_depth_buffer_float_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_ARB_shader_stencil_export"))
{
ARB_shader_stencil_export_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_NV_fragment_shader_barycentric"))
{
NV_fragment_shader_barycentric_supported = true;
find_count--;
continue;
}
if (check(ext_name, "GL_AMD_pinned_memory"))
{
AMD_pinned_memory = true;
find_count--;
continue;
}
all_extensions.emplace(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
}
#define CHECK_EXTENSION_SUPPORT(extension_short_name)\
do {\
if (all_extensions.contains("GL_"#extension_short_name)) {\
extension_short_name##_supported = true;\
rsx_log.success("[CAPS] Using GL_"#extension_short_name);\
continue;\
} \
} while (0)
CHECK_EXTENSION_SUPPORT(ARB_shader_draw_parameters);
CHECK_EXTENSION_SUPPORT(EXT_direct_state_access);
CHECK_EXTENSION_SUPPORT(ARB_direct_state_access);
CHECK_EXTENSION_SUPPORT(ARB_bindless_texture);
CHECK_EXTENSION_SUPPORT(ARB_buffer_storage);
CHECK_EXTENSION_SUPPORT(ARB_texture_buffer_object);
CHECK_EXTENSION_SUPPORT(ARB_depth_buffer_float);
CHECK_EXTENSION_SUPPORT(ARB_texture_barrier);
CHECK_EXTENSION_SUPPORT(NV_texture_barrier);
CHECK_EXTENSION_SUPPORT(NV_gpu_shader5);
CHECK_EXTENSION_SUPPORT(AMD_gpu_shader_half_float);
CHECK_EXTENSION_SUPPORT(ARB_compute_shader);
CHECK_EXTENSION_SUPPORT(EXT_depth_bounds_test);
CHECK_EXTENSION_SUPPORT(NV_depth_buffer_float);
CHECK_EXTENSION_SUPPORT(ARB_shader_stencil_export);
CHECK_EXTENSION_SUPPORT(NV_fragment_shader_barycentric);
CHECK_EXTENSION_SUPPORT(AMD_pinned_memory);
CHECK_EXTENSION_SUPPORT(ARB_shader_texture_image_samples);
CHECK_EXTENSION_SUPPORT(EXT_texture_compression_s3tc);
#undef CHECK_EXTENSION_SUPPORT
// Set GLSL version
glsl_version = version_info(reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)));
@@ -214,17 +133,19 @@ namespace gl
// Texture buffers moved into core at GL 3.3
if (version_major > 3 || (version_major == 3 && version_minor >= 3))
ARB_texture_buffer_supported = true;
ARB_texture_buffer_object_supported = true;
#ifndef USE_GLES
// Check for expected library entry-points for some required functions
if (!ARB_buffer_storage_supported && glNamedBufferStorage && glMapNamedBufferRange)
ARB_buffer_storage_supported = true;
if (!ARB_dsa_supported && glGetTextureImage && glTextureBufferRange)
ARB_dsa_supported = true;
if (!ARB_direct_state_access_supported && glGetTextureImage && glTextureBufferRange)
ARB_direct_state_access_supported = true;
if (!EXT_dsa_supported && glGetTextureImageEXT && glTextureBufferRangeEXT)
EXT_dsa_supported = true;
if (!EXT_direct_state_access_supported && glGetTextureImageEXT && glTextureBufferRangeEXT)
EXT_direct_state_access_supported = true;
#endif
}
else if (!vendor_MESA && vendor_string.find("nvidia") != umax)
{

View File

@@ -23,13 +23,13 @@ namespace gl
bool initialized = false;
version_info glsl_version;
bool EXT_dsa_supported = false;
bool EXT_depth_bounds_test = false;
bool AMD_pinned_memory = false;
bool ARB_dsa_supported = false;
bool EXT_direct_state_access_supported = false;
bool EXT_depth_bounds_test_supported = false;
bool AMD_pinned_memory_supported = false;
bool ARB_direct_state_access_supported = false;
bool ARB_bindless_texture_supported = false;
bool ARB_buffer_storage_supported = false;
bool ARB_texture_buffer_supported = false;
bool ARB_texture_buffer_object_supported = false;
bool ARB_shader_draw_parameters_supported = false;
bool ARB_depth_buffer_float_supported = false;
bool ARB_texture_barrier_supported = false;
@@ -40,6 +40,8 @@ namespace gl
bool ARB_compute_shader_supported = false;
bool NV_depth_buffer_float_supported = false;
bool NV_fragment_shader_barycentric_supported = false;
bool ARB_shader_texture_image_samples_supported = false;
bool EXT_texture_compression_s3tc_supported = false;
bool vendor_INTEL = false; // has broken GLSL compiler
bool vendor_AMD = false; // has broken ARB_multidraw
@@ -50,9 +52,6 @@ namespace gl
bool subvendor_ATI = false; // Pre-GCN cards (terascale, evergreen)
void initialize();
private:
bool check(const std::string& ext_name, const char* test);
};
const capabilities& get_driver_caps();

View File

@@ -20,29 +20,31 @@
#define GL_RASTERIZER_STATE_BIND_SLOT UBO_SLOT(6)
#define GL_INTERPRETER_VERTEX_BLOCK SSBO_SLOT(0)
#define GL_INTERPRETER_FRAGMENT_BLOCK SSBO_SLOT(1)
#define GL_INSTANCING_LUT_BIND_SLOT SSBO_SLOT(2)
#define GL_INSTANCING_XFORM_CONSTANTS_SLOT SSBO_SLOT(3)
#define GL_COMPUTE_BUFFER_SLOT(index) SSBO_SLOT(2 + index)
#define GL_COMPUTE_IMAGE_SLOT(index) SSBO_SLOT(index)
//Function call wrapped in ARB_DSA vs EXT_DSA compat check
#define DSA_CALL(func, object_name, target, ...)\
if (::gl::get_driver_caps().ARB_dsa_supported)\
if (::gl::get_driver_caps().ARB_direct_state_access_supported)\
gl##func(object_name, __VA_ARGS__);\
else\
gl##func##EXT(object_name, target, __VA_ARGS__);
#define DSA_CALL2(func, ...)\
if (::gl::get_driver_caps().ARB_dsa_supported)\
if (::gl::get_driver_caps().ARB_direct_state_access_supported)\
gl##func(__VA_ARGS__);\
else\
gl##func##EXT(__VA_ARGS__);
#define DSA_CALL2_RET(func, ...)\
(::gl::get_driver_caps().ARB_dsa_supported) ?\
(::gl::get_driver_caps().ARB_direct_state_access_supported) ?\
gl##func(__VA_ARGS__) :\
gl##func##EXT(__VA_ARGS__)
#define DSA_CALL3(funcARB, funcDSA, ...)\
if (::gl::get_driver_caps().ARB_dsa_supported)\
if (::gl::get_driver_caps().ARB_direct_state_access_supported)\
gl##funcARB(__VA_ARGS__);\
else\
gl##funcDSA##EXT(__VA_ARGS__);
@@ -73,13 +75,13 @@ namespace gl
glBindBuffer(BindId, m_last_binding);
}
};
#ifndef USE_GLES
// Very useful util when capturing traces with RenderDoc
static inline void push_debug_label(const char* label)
{
glInsertEventMarkerEXT(static_cast<GLsizei>(strlen(label)), label);
}
#endif
// Checks if GL state is still valid
static inline void check_state()
{

View File

@@ -50,8 +50,13 @@ namespace gl
bool fbo::check() const
{
GLenum status = DSA_CALL2_RET(CheckNamedFramebufferStatus, m_id, GL_FRAMEBUFFER);
#ifndef USE_GLES
GLenum status = DSA_CALL2_RET(CheckNamedFramebufferStatus, m_id, GL_FRAMEBUFFER);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
#endif
if (status != GL_FRAMEBUFFER_COMPLETE)
{
rsx_log.error("FBO check failed: 0x%04x", status);
@@ -72,13 +77,24 @@ namespace gl
void fbo::draw_buffer(const attachment& buffer) const
{
GLenum buf = buffer.id();
#ifndef USE_GLES
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, 1, &buf);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
glDrawBuffers(1, &buf);
#endif
}
void fbo::draw_buffer(swapchain_buffer buffer) const
{
GLenum buf = static_cast<GLenum>(buffer);
#ifndef USE_GLES
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, 1, &buf);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
glDrawBuffers(1, &buf);
#endif
}
void fbo::draw_buffers(const std::initializer_list<attachment>& indexes) const
@@ -89,18 +105,33 @@ namespace gl
for (auto& index : indexes)
ids.push_back(index.id());
#ifndef USE_GLES
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, static_cast<GLsizei>(ids.size()), ids.data());
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
glDrawBuffers(static_cast<GLsizei>(ids.size()), ids.data());
#endif
}
void fbo::read_buffer(const attachment& buffer) const
{
#ifndef USE_GLES
DSA_CALL3(NamedFramebufferReadBuffer, FramebufferReadBuffer, m_id, buffer.id());
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
glReadBuffer(buffer.id());
#endif
}
void fbo::read_buffer(swapchain_buffer buffer) const
{
GLenum buf = static_cast<GLenum>(buffer);
#ifndef USE_GLES
DSA_CALL3(NamedFramebufferReadBuffer, FramebufferReadBuffer, m_id, buf);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
glReadBuffer(buf);
#endif
}
void fbo::draw_arrays(GLenum mode, GLsizei count, GLint first) const
@@ -181,7 +212,6 @@ namespace gl
glClear(static_cast<GLbitfield>(buffers_));
}
#ifndef __ANDROID__
void fbo::copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const
{
save_binding_state save(*this);
@@ -196,131 +226,7 @@ namespace gl
pixel_settings.apply();
glDrawPixels(size.width, size.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr);
}
#else
void fbo::_draw_textured_quad(GLuint texture, const sizei& size) const {
// 0. 确保有可用的着色器程序
static GLuint program = 0;
static GLint aPos = -1, aTexCoord = -1, uTex = -1;
if (program == 0) {
// 顶点着色器
const char* vsrc = R"(
attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
gl_Position = aPosition;
vTexCoord = aTexCoord;
}
)";
// 片段着色器
const char* fsrc = R"(
precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D uTexture;
void main() {
gl_FragColor = texture2D(uTexture, vTexCoord);
}
)";
program = _compile_shader_program(vsrc, fsrc); // 需实现编译链接着色器的函数
aPos = glGetAttribLocation(program, "aPosition");
aTexCoord = glGetAttribLocation(program, "aTexCoord");
uTex = glGetUniformLocation(program, "uTexture");
}
// 1. 设置视口和混合状态
glViewport(0, 0, size.width, size.height);
glDisable(GL_BLEND); // 根据需要调整
// 2. 绑定纹理和着色器
glUseProgram(program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(uTex, 0);
// 3. 定义顶点数据(全屏四边形)
const float vertices[] = {
-1.0f, -1.0f, 0.0f, 0.0f, // 左下
1.0f, -1.0f, 1.0f, 0.0f, // 右下
-1.0f, 1.0f, 0.0f, 1.0f, // 左上
1.0f, 1.0f, 1.0f, 1.0f // 右上
};
// 4. 渲染
GLuint vao, vbo;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
glEnableVertexAttribArray(aPos);
glVertexAttribPointer(aPos, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glEnableVertexAttribArray(aTexCoord);
glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// 5. 清理临时缓冲对象
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
}
void fbo::copy_from(
const void* pixels,
const sizei& size,
gl::texture::format format_,
gl::texture::type type_,
class pixel_unpack_settings pixel_settings
) const {
save_binding_state save(*this);
pixel_settings.apply();
// 1. 创建临时纹理并上传像素数据
GLuint tempTex;
glGenTextures(1, &tempTex);
glBindTexture(GL_TEXTURE_2D, tempTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(
GL_TEXTURE_2D, 0, static_cast<GLenum>(format_),
size.width, size.height, 0,
static_cast<GLenum>(format_), static_cast<GLenum>(type_), pixels
);
// 2. 渲染全屏四边形
_draw_textured_quad(tempTex, size);
// 3. 清理临时纹理
glDeleteTextures(1, &tempTex);
}
void fbo::copy_from(
const buffer& buf,
const sizei& size,
gl::texture::format format_,
gl::texture::type type_,
class pixel_unpack_settings pixel_settings
) const {
save_binding_state save(*this);
buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf);
pixel_settings.apply();
// 1. 创建临时纹理并从PBO上传数据
GLuint tempTex;
glGenTextures(1, &tempTex);
glBindTexture(GL_TEXTURE_2D, tempTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(
GL_TEXTURE_2D, 0, static_cast<GLenum>(format_),
size.width, size.height, 0,
static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr // 数据来自PBO
);
// 2. 渲染全屏四边形
_draw_textured_quad(tempTex, size);
// 3. 清理临时纹理
glDeleteTextures(1, &tempTex);
}
#endif
void fbo::copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const
{
save_binding_state save(*this);

View File

@@ -125,15 +125,21 @@ namespace gl
void operator = (const texture& rhs)
{
ensure(rhs.get_target() == texture::target::texture2D);
ensure(rhs.get_target() == texture::target::texture2D ||
rhs.get_target() == texture::target::texture2DMS);
m_parent.m_resource_bindings[m_id] = rhs.id();
#ifndef USE_GLES
DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs.id(), 0);
#endif
}
void operator = (const GLuint rhs)
{
m_parent.m_resource_bindings[m_id] = rhs;
DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs, 0);
#ifndef USE_GLES
DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs, 0);
#endif
}
};
@@ -219,12 +225,7 @@ namespace gl
void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLuint* indices) const;
void clear(buffers buffers_) const;
#ifdef __ANDROID__
void fbo::_draw_textured_quad(GLuint texture, const sizei& size) const;
#endif
void copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const;
void copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const;

View File

@@ -19,8 +19,24 @@ namespace gl
}
}
texture::texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, rsx::format_class format_class)
texture::texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLubyte samples, GLenum sized_format, rsx::format_class format_class)
{
// Upgrade targets for MSAA
if (samples > 1)
{
switch (target)
{
case GL_TEXTURE_2D:
target = GL_TEXTURE_2D_MULTISAMPLE;
break;
case GL_TEXTURE_2D_ARRAY:
target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
break;
default:
fmt::throw_exception("MSAA is only supported on 2D images. Target=0x%x", target);
}
}
glGenTextures(1, &m_id);
// Must bind to initialize the new texture
@@ -40,30 +56,45 @@ namespace gl
glTexStorage2D(target, mipmaps, storage_fmt, width, height);
depth = 1;
break;
case GL_TEXTURE_2D_MULTISAMPLE:
ensure(mipmaps == 1);
glTexStorage2DMultisample(target, samples, storage_fmt, width, height, GL_TRUE);
depth = 1;
break;
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
glTexStorage3D(target, mipmaps, storage_fmt, width, height, depth);
break;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
ensure(mipmaps == 1);
glTexStorage3DMultisample(target, samples, storage_fmt, width, height, depth, GL_TRUE);
break;
case GL_TEXTURE_BUFFER:
break;
}
if (target != GL_TEXTURE_BUFFER)
{
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
if (samples == 1)
{
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
}
m_width = width;
m_height = height;
m_depth = depth;
m_mipmaps = mipmaps;
m_samples = samples;
m_aspect_flags = image_aspect::color;
ensure(width > 0 && height > 0 && depth > 0 && mipmaps > 0 && samples > 0, "Invalid OpenGL texture definition.");
switch (storage_fmt)
{
case GL_DEPTH_COMPONENT16:
@@ -146,6 +177,8 @@ namespace gl
void texture::copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
{
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
pixel_settings.apply();
switch (const auto target_ = static_cast<GLenum>(m_target))
@@ -157,18 +190,30 @@ namespace gl
}
case GL_TEXTURE_2D:
{
#ifdef USE_GLES
glBindTexture(target_,m_id);
glTexSubImage2D(target_, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
#else
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
#endif
break;
}
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
{
#ifdef USE_GLES
glBindTexture(target_,m_id);
glTexSubImage3D( target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
#else
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
#endif
break;
}
case GL_TEXTURE_CUBE_MAP:
{
if (get_driver_caps().ARB_dsa_supported)
if (get_driver_caps().ARB_direct_state_access_supported)
{
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
}
@@ -190,6 +235,8 @@ namespace gl
void texture::copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length)
{
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
if (get_target() != target::textureBuffer)
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
@@ -203,18 +250,20 @@ namespace gl
void texture::copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
{
ensure(m_samples <= 1, "Transfer operations are unsupported on multisampled textures.");
pixel_settings.apply();
const auto& caps = get_driver_caps();
if (!region.x && !region.y && !region.z &&
region.width == m_width && region.height == m_height && region.depth == m_depth)
{
if (caps.ARB_dsa_supported)
if (caps.ARB_direct_state_access_supported)
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
else
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst);
}
else if (caps.ARB_dsa_supported)
else if (caps.ARB_direct_state_access_supported)
{
glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth,
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
@@ -223,7 +272,7 @@ namespace gl
{
// Worst case scenario. For some reason, EXT_dsa does not have glGetTextureSubImage
const auto target_ = static_cast<GLenum>(m_target);
texture tmp{ target_, region.width, region.height, region.depth, 1, static_cast<GLenum>(m_internal_format) };
texture tmp{ target_, region.width, region.height, region.depth, 1, 1, static_cast<GLenum>(m_internal_format), m_format_class };
glCopyImageSubData(m_id, target_, level, region.x, region.y, region.z, tmp.id(), target_, 0, 0, 0, 0,
region.width, region.height, region.depth);

View File

@@ -45,7 +45,8 @@ namespace gl
enum remap_constants : u32
{
GL_REMAP_IDENTITY = 0xCAFEBABE,
GL_REMAP_BGRA = 0x0000AA6C
GL_REMAP_BGRA = 0x0000AA6C,
GL_REMAP_VIEW_MULTISAMPLED = 0xDEADBEEF
};
struct subresource_range
@@ -68,19 +69,27 @@ namespace gl
ushort = GL_UNSIGNED_SHORT,
uint = GL_UNSIGNED_INT,
#ifndef USE_GLES
ubyte_3_3_2 = GL_UNSIGNED_BYTE_3_3_2,
//ubyte_2_3_3_rev = GL_UNSIGNED_BYTE_2_3_3_REV,
ubyte_2_3_3_rev = GL_UNSIGNED_BYTE_2_3_3_REV,
ushort_5_6_5 = GL_UNSIGNED_SHORT_5_6_5,
//ushort_5_6_5_rev = GL_UNSIGNED_SHORT_5_6_5_REV,
ushort_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4,
//ushort_4_4_4_4_rev = GL_UNSIGNED_SHORT_4_4_4_4_REV,
ushort_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1,
//ushort_1_5_5_5_rev = GL_UNSIGNED_SHORT_1_5_5_5_REV,
//uint_8_8_8_8 = GL_UNSIGNED_INT_8_8_8_8,
ushort_5_6_5_rev = GL_UNSIGNED_SHORT_5_6_5_REV,
ushort_4_4_4_4_rev = GL_UNSIGNED_SHORT_4_4_4_4_REV,
ushort_1_5_5_5_rev = GL_UNSIGNED_SHORT_1_5_5_5_REV,
uint_8_8_8_8 = GL_UNSIGNED_INT_8_8_8_8,
uint_8_8_8_8_rev = GL_UNSIGNED_INT_8_8_8_8_REV,
//uint_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2,
uint_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2,
f64 = GL_DOUBLE,
#endif
ushort_5_6_5 = GL_UNSIGNED_SHORT_5_6_5,
ushort_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4,
ushort_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1,
uint_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV,
uint_24_8 = GL_UNSIGNED_INT_24_8,
float32_uint8 = GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
@@ -90,7 +99,6 @@ namespace gl
sint = GL_INT,
f16 = GL_HALF_FLOAT,
f32 = GL_FLOAT,
//f64 = GL_DOUBLE,
};
enum class channel
@@ -110,9 +118,10 @@ namespace gl
rgb = GL_RGB,
rgba = GL_RGBA,
#ifndef USE_GLES
bgr = GL_BGR,
bgra = GL_BGRA,
#endif
stencil = GL_STENCIL_INDEX,
depth = GL_DEPTH_COMPONENT,
depth_stencil = GL_DEPTH_STENCIL
@@ -126,11 +135,12 @@ namespace gl
depth24_stencil8 = GL_DEPTH24_STENCIL8,
depth32f_stencil8 = GL_DEPTH32F_STENCIL8,
//compressed_rgb_s3tc_dxt1 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
//compressed_rgba_s3tc_dxt1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
//compressed_rgba_s3tc_dxt3 = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
//compressed_rgba_s3tc_dxt5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
#ifndef USE_GLES
compressed_rgb_s3tc_dxt1 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
compressed_rgba_s3tc_dxt1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
compressed_rgba_s3tc_dxt3 = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
compressed_rgba_s3tc_dxt5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
#endif
//Sized internal formats, see opengl spec document on glTexImage2D, table 3
rgba8 = GL_RGBA8,
bgra8 = GL_BGRA8,
@@ -139,10 +149,16 @@ namespace gl
bgr5a1 = GL_BGR5_A1,
rgba4 = GL_RGBA4,
r8 = GL_R8,
//r16 = GL_R16,
#ifndef USE_GLES
r16 = GL_R16,
#endif
r32f = GL_R32F,
rg8 = GL_RG8,
//rg16 = GL_RG16,
#ifndef USE_GLES
rg16 = GL_RG16,
#endif
rg16f = GL_RG16F,
rgba16f = GL_RGBA16F,
rgba32f = GL_RGBA32F,
@@ -156,9 +172,12 @@ namespace gl
mirrored_repeat = GL_MIRRORED_REPEAT,
clamp_to_edge = GL_CLAMP_TO_EDGE,
clamp_to_border = GL_CLAMP_TO_BORDER,
//mirror_clamp = GL_MIRROR_CLAMP_EXT,
#ifndef USE_GLES
mirror_clamp = GL_MIRROR_CLAMP_EXT,
//mirror_clamp_to_edge = GL_MIRROR_CLAMP_TO_EDGE,
mirror_clamp_to_border = GL_MIRROR_CLAMP_TO_BORDER_EXT
#endif
};
enum class compare_mode
@@ -169,12 +188,16 @@ namespace gl
enum class target
{
#ifndef USE_GLES
texture1D = GL_TEXTURE_1D,
#endif
texture2D = GL_TEXTURE_2D,
texture3D = GL_TEXTURE_3D,
textureCUBE = GL_TEXTURE_CUBE_MAP,
textureBuffer = GL_TEXTURE_BUFFER,
texture2DArray = GL_TEXTURE_2D_ARRAY
texture2DArray = GL_TEXTURE_2D_ARRAY,
texture2DMS = GL_TEXTURE_2D_MULTISAMPLE
};
protected:
@@ -183,6 +206,7 @@ namespace gl
GLuint m_height = 0;
GLuint m_depth = 0;
GLuint m_mipmaps = 0;
GLubyte m_samples = 0;
GLuint m_pitch = 0;
GLuint m_compressed = GL_FALSE;
GLuint m_aspect_flags = 0;
@@ -197,7 +221,7 @@ namespace gl
texture(const texture&) = delete;
texture(texture&& texture_) = delete;
texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, rsx::format_class format_class = rsx::RSX_FORMAT_CLASS_UNDEFINED);
texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLubyte samples, GLenum sized_format, rsx::format_class format_class);
virtual ~texture();
// Getters/setters
@@ -214,6 +238,7 @@ namespace gl
return m_target;
}
#ifndef USE_GLES
static bool compressed_format(internal_format format_) noexcept
{
switch (format_)
@@ -227,7 +252,7 @@ namespace gl
return false;
}
}
#endif
uint id() const noexcept
{
return m_id;
@@ -276,9 +301,9 @@ namespace gl
return m_pitch;
}
constexpr GLubyte samples() const
GLubyte samples() const
{
return 1;
return m_samples;
}
GLboolean compressed() const

View File

@@ -18,13 +18,16 @@ namespace gl
public:
void apply() const
{
#ifndef USE_GLES
glPixelStorei(GL_PACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE);
glPixelStorei(GL_PACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE);
glPixelStorei(GL_PACK_ROW_LENGTH, m_row_length);
glPixelStorei(GL_PACK_IMAGE_HEIGHT, m_image_height);
glPixelStorei(GL_PACK_SKIP_IMAGES, m_skip_images);
#endif
glPixelStorei(GL_PACK_ROW_LENGTH, m_row_length);
glPixelStorei(GL_PACK_SKIP_ROWS, m_skip_rows);
glPixelStorei(GL_PACK_SKIP_PIXELS, m_skip_pixels);
glPixelStorei(GL_PACK_SKIP_IMAGES, m_skip_images);
glPixelStorei(GL_PACK_ALIGNMENT, m_alignment);
}
@@ -93,8 +96,10 @@ namespace gl
public:
void apply() const
{
#ifndef USE_GLES
glPixelStorei(GL_UNPACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE);
glPixelStorei(GL_UNPACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE);
#endif
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_row_length);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_image_height);
glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skip_rows);

View File

@@ -181,12 +181,13 @@ namespace gl
return *this;
}
#ifndef USE_GLES
program& bind_fragment_data_location(const std::string& name, int color_number)
{
glBindFragDataLocation(m_id, color_number, name.c_str());
return *this;
}
#endif
GLuint id() const { return m_id; }
bool created() const { return m_id != GL_NONE; }

View File

@@ -14,12 +14,18 @@ namespace gl
buffer::create();
save_binding_state save(current_target(), *this);
#ifndef USE_GLES
GLbitfield buffer_storage_flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
if (gl::get_driver_caps().vendor_MESA) buffer_storage_flags |= GL_CLIENT_STORAGE_BIT;
DSA_CALL2(NamedBufferStorage, m_id, size, data, buffer_storage_flags);
m_memory_mapping = DSA_CALL2_RET(MapNamedBufferRange, m_id, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
#else
GLbitfield buffer_storage_flags = GL_MAP_WRITE_BIT;
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBufferData(GL_ARRAY_BUFFER, size, data, buffer_storage_flags);
m_memory_mapping = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, buffer_storage_flags);
#endif
ensure(m_memory_mapping != nullptr);
m_data_loc = 0;
m_size = ::narrow<u32>(size);
@@ -115,7 +121,12 @@ namespace gl
m_data_loc = 0;
}
#ifndef USE_GLES
m_memory_mapping = DSA_CALL2_RET(MapNamedBufferRange, m_id, m_data_loc, block_size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
#else
glBindBuffer(GL_ARRAY_BUFFER, m_id);
m_memory_mapping = glMapBufferRange(GL_ARRAY_BUFFER, m_data_loc, block_size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
#endif
m_mapped_bytes = block_size;
m_mapping_offset = m_data_loc;
m_alignment_offset = 0;
@@ -187,7 +198,13 @@ namespace gl
flush();
dirty = true;
#ifndef USE_GLES
return DSA_CALL2_RET(MapNamedBufferRange, m_id, offset, length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
#else
glBindBuffer(GL_ARRAY_BUFFER, m_id);
return glMapBufferRange(GL_ARRAY_BUFFER, offset, length, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
#endif
}
void transient_ring_buffer::bind()
@@ -206,8 +223,13 @@ namespace gl
buffer::create();
save_binding_state save(current_target(), *this);
DSA_CALL2(NamedBufferStorage, m_id, size, data, GL_MAP_WRITE_BIT);
#ifndef USE_GLES
DSA_CALL2(NamedBufferStorage, m_id, size, data, GL_MAP_WRITE_BIT);
#else
glBindBuffer(GL_ARRAY_BUFFER, m_id);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_MAP_WRITE_BIT);
#endif
m_data_loc = 0;
m_size = ::narrow<u32>(size);
m_memory_type = memory_type::host_visible;

View File

@@ -2,7 +2,6 @@
#include "sampler.h"
#include "Emu/RSX/gcm_enums.h"
#include "Emu/RSX/rsx_utils.h"
#include "Emu/RSX/Common/TextureUtils.h"
//GLenum wrap_mode(rsx::texture_wrap_mode wrap);

View File

@@ -137,7 +137,7 @@ namespace gl
const u32 value = std::bit_cast<u32>(depth);
if (!test_and_set_property(GL_DEPTH_CLEAR_VALUE, value))
{
glClearDepth(depth);
glClearDepthf(depth);
}
}
@@ -240,6 +240,7 @@ namespace gl
const u64 value = (static_cast<u64>(std::bit_cast<u32>(max)) << 32) | std::bit_cast<u32>(min);
if (!test_and_set_property(DEPTH_BOUNDS, value))
{
#ifndef USE_GLES
if (get_driver_caps().NV_depth_buffer_float_supported)
{
glDepthBoundsdNV(min, max);
@@ -248,6 +249,7 @@ namespace gl
{
glDepthBoundsEXT(min, max);
}
#endif
}
}
@@ -256,6 +258,7 @@ namespace gl
const u64 value = (static_cast<u64>(std::bit_cast<u32>(max)) << 32) | std::bit_cast<u32>(min);
if (!test_and_set_property(DEPTH_RANGE, value))
{
#ifndef USE_GLES
if (get_driver_caps().NV_depth_buffer_float_supported)
{
glDepthRangedNV(min, max);
@@ -264,15 +267,18 @@ namespace gl
{
glDepthRange(min, max);
}
#endif
}
}
void logic_op(GLenum op)
{
#ifndef USE_GLES
if (!test_and_set_property(GL_COLOR_LOGIC_OP, op))
{
glLogicOp(op);
}
#endif
}
void line_width(GLfloat width)
@@ -309,12 +315,39 @@ namespace gl
}
}
void sample_mask(GLbitfield mask)
{
if (!test_and_set_property(GL_SAMPLE_MASK_VALUE, mask))
{
glSampleMaski(0, mask);
}
}
void sample_coverage(GLclampf coverage)
{
const u32 value = std::bit_cast<u32>(coverage);
if (!test_and_set_property(GL_SAMPLE_COVERAGE_VALUE, value))
{
glSampleCoverage(coverage, GL_FALSE);
}
}
void min_sample_shading_rate(GLclampf rate)
{
const u32 value = std::bit_cast<u32>(rate);
if (!test_and_set_property(GL_MIN_SAMPLE_SHADING_VALUE, value))
{
glMinSampleShading(rate);
}
}
void clip_planes(GLuint mask)
{
if (!test_and_set_property(CLIP_PLANES, mask))
{
for (u32 i = 0; i < 6; ++i)
{
#ifndef USE_GLES
if (mask & (1 << i))
{
glEnable(GL_CLIP_DISTANCE0 + i);
@@ -323,6 +356,7 @@ namespace gl
{
glDisable(GL_CLIP_DISTANCE0 + i);
}
#endif
}
}
}

View File

@@ -22,7 +22,9 @@ namespace gl
u32 = GL_UNSIGNED_INT,
f16 = GL_HALF_FLOAT,
f32 = GL_FLOAT,
f64 = GL_DOUBLE,
#ifndef USE_GLES
f64 = GL_DOUBLE,
#endif
fixed = GL_FIXED,
s32_2_10_10_10_rev = GL_INT_2_10_10_10_REV,
u32_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV,
@@ -285,16 +287,17 @@ namespace gl
}
void operator = (float rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs); }
void operator = (double rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs); }
void operator = (const color1f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs.r); }
#ifndef USE_GLES
void operator = (double rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs); }
void operator = (const color1d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs.r); }
void operator = (const color2f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); }
void operator = (const color2d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2d(location(), rhs.r, rhs.g); }
void operator = (const color3f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); }
void operator = (const color3d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3d(location(), rhs.r, rhs.g, rhs.b); }
void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); }
void operator = (const color4d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); }
#endif
void operator = (const color1f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs.r); }
void operator = (const color2f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); }
void operator = (const color3f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); }
void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); }
void operator = (buffer_pointer& pointer) const
{

View File

@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "../../glutils/fbo.h"
#include "../fsr_pass.h"
#if defined(__GNUC__)
@@ -177,7 +178,7 @@ namespace gl
{
return std::make_unique<gl::viewable_image>(
GL_TEXTURE_2D,
output_w, output_h, 1, 1,
output_w, output_h, 1, 1, 1,
GL_RGBA8, RSX_FORMAT_CLASS_COLOR);
};

View File

@@ -1,8 +1,5 @@
#pragma once
#include "util/types.hpp"
#include "../glutils/fbo.h"
#include "../glutils/image.h"
#include "../glutils/state_tracker.hpp"

View File

@@ -2753,18 +2753,22 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
{
gcm_format = (surface->get_surface_depth_format() != rsx::surface_depth_format::z16) ? CELL_GCM_TEXTURE_DEPTH16 : CELL_GCM_TEXTURE_DEPTH24_D8;
swap_bytes = true;
m_texture_cache.lock_memory_region(
*m_current_command_buffer, surface, surface->get_memory_range(), false,
surface->get_surface_width<rsx::surface_metrics::pixels>(), surface->get_surface_height<rsx::surface_metrics::pixels>(), surface->get_rsx_pitch(),
gcm_format, swap_bytes);
}
else
{
auto info = get_compatible_gcm_format(surface->get_surface_color_format());
gcm_format = info.first;
swap_bytes = info.second;
}
m_texture_cache.lock_memory_region(
*m_current_command_buffer, surface, surface->get_memory_range(), false,
surface->get_surface_width<rsx::surface_metrics::pixels>(), surface->get_surface_height<rsx::surface_metrics::pixels>(), surface->get_rsx_pitch(),
gcm_format, swap_bytes);
m_texture_cache.lock_memory_region(
*m_current_command_buffer, surface, surface->get_memory_range(), false,
surface->get_surface_width<rsx::surface_metrics::pixels>(), surface->get_surface_height<rsx::surface_metrics::pixels>(), surface->get_rsx_pitch(),
gcm_format, info.second);
}
}
m_rtts.orphaned_surfaces.clear();

View File

@@ -1,7 +1,7 @@
// Wrangler for Vulkan functions.
// TODO: Eventually, we shall declare vulkan with NO_PROTOTYPES and wrap everything here for android multi-driver support.
// For now, we just use it for extensions since we're on VK_1_0
#if 1
#if defined(DECL_VK_FUNCTION)
#define VK_FUNC(func) extern PFN_##func _##func
#elif defined(DEF_VK_FUNCTION)
@@ -11,7 +11,30 @@
#else
#error ""
#endif
#else
#if defined(DECL_VK_FUNCTION)
#define VK_FUNC(func) extern int n_##func;\
template<typename... Args> \
auto _##func(Args&&... args)->decltype(func(args...)){ \
++n_##func;return func(std::forward<Args>(args)...);\
}
#elif defined(DEF_VK_FUNCTION)
#define VK_FUNC(func) int n_##func=0
#elif defined(LOAD_VK_FUNCTION)
#define VK_FUNC(func)
#elif defined(CLEAR_N_VK_FUNCTION)
#define VK_FUNC(func) n_##func=0
#elif defined(PRINT_N_VK_FUNCTION)
#define VK_FUNC(func) if(n_##func) rsx_log.warning("#### %s: %d",#func,n_##func)
#else
#error ""
#endif
#endif
VK_FUNC(vkCreateInstance);
VK_FUNC(vkDestroyInstance);
VK_FUNC(vkEnumeratePhysicalDevices);
@@ -165,7 +188,7 @@ VK_FUNC(vkAcquireNextImageKHR);
VK_FUNC(vkQueuePresentKHR);
#if defined(DECL_VK_FUNCTION)||defined(DEF_VK_FUNCTION)
#if defined(DECL_VK_FUNCTION)||defined(DEF_VK_FUNCTION)||defined(CLEAR_N_VK_FUNCTION)||defined(PRINT_N_VK_FUNCTION)
#define INSTANCE_VK_FUNCTION
#define DEVICE_VK_FUNCTION
#include "VKPFNTableEXT.h"

View File

@@ -53,7 +53,7 @@ namespace vk
std::unique_ptr<glsl::program> pipe_compiler::int_compile_compute_pipe(const VkComputePipelineCreateInfo& create_info, VkPipelineLayout pipe_layout)
{
VkPipeline pipeline;
//FIXME 部分Adreno 7xx默认驱动会返回-13
//FIXME 部分Adreno 7xx默认驱动可能会返回-13
CHECK_RESULT(_vkCreateComputePipelines(*g_render_device, nullptr, 1, &create_info, nullptr, &pipeline));
return std::make_unique<vk::glsl::program>(*m_device, pipeline, pipe_layout);
}

View File

@@ -29,9 +29,9 @@ namespace
[[fallthrough]];
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8:
return use_bgra_fmt?VK_FORMAT_B8G8R8A8_UNORM:VK_FORMAT_R8G8B8A8_UNORM;
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8:
return use_bgra_fmt?VK_FORMAT_R8G8B8A8_UNORM:VK_FORMAT_B8G8R8A8_UNORM;
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT:
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8:
return use_bgra_fmt?VK_FORMAT_R8G8B8A8_UNORM:VK_FORMAT_B8G8R8A8_UNORM;
case CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT:
return VK_FORMAT_R16G16B16A16_SFLOAT;
}
}
@@ -830,20 +830,33 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
}
}
#if 0
static u64 count=0;
static int64_t last_gpu_mem=0;
static int64_t last_use_mem=0;
if((++count%2)==0)
{
{
if(static_cast<int64_t>(meminfo_gpu_mem_usage_kb())-last_gpu_mem>16*1024) {
rsx_log.warning("aaaa %f mb",
(static_cast<int64_t>(meminfo_gpu_mem_usage_kb()) -
last_gpu_mem) / 1024.0f);
}
else
rsx_log.warning("bbbb %f mb",(static_cast<int64_t>(meminfo_gpu_mem_usage_kb())-last_gpu_mem)/1024.0f);
#define PRINT_N_VK_FUNCTION
{
#include "VKPFNTable.h"
};
#undef PRINT_N_VK_FUNCTION
if(last_use_mem==0){
meminfo_init();
#define CLEAR_N_VK_FUNCTION
{
#include "VKPFNTable.h"
};
#undef CLEAR_N_VK_FUNCTION
}
last_gpu_mem = static_cast<int64_t>(meminfo_gpu_mem_usage_kb());
}
const std::vector<mem_map_entry_t> mem_info=meminfo_update();
int64_t cur_use_mem= static_cast<int64_t>(meminfo_calc_total_mem(mem_info));
if(cur_use_mem-last_use_mem>1024*1024){
rsx_log.warning("aaaa %f mb",static_cast<float>(cur_use_mem-last_use_mem)/1024.0f/1024.0f);
}
last_use_mem=cur_use_mem;
#endif
if (g_cfg.video.debug_overlay)
{
@@ -900,18 +913,23 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
}
else if(g_cfg.misc.mem_debug_overlay){
#if 0
const std::string usage= meminfo_print_calc_total_mem(mem_info);
const std::string detail= meminfo_to_string(mem_info,4);
const std::string usage= std::to_string(meminfo_sys_mem_usage(100.f));
const std::string gpu_usage=std::to_string(last_gpu_mem/1024.f);//meminfo_gpu_mem_usage();
rsx::overlays::set_debug_overlay_text(fmt::format(
"usage: %s\n"
"detail:\n"
"%s \n",
usage,detail)
"gpu: %s",
usage,gpu_usage)
);
#else
const u32 mem_usage= static_cast<u32>(meminfo_sys_mem_usage(100.f));
rsx::overlays::set_debug_overlay_text(fmt::format("%02u%%",mem_usage));
const uint64_t gpu_usage= meminfo_gpu_mem_usage_kb();
if(gpu_usage!=0)
rsx::overlays::set_debug_overlay_text( fmt::format("total usage: %02u%%\n gpu usage: %2f GB"
,mem_usage,gpu_usage/1024.f/1024.f));
else
rsx::overlays::set_debug_overlay_text( fmt::format("total usage: %02u%%"
,mem_usage));
#endif
}

View File

@@ -319,7 +319,7 @@ namespace vk
rp_info.pSubpasses = &subpass;
VkRenderPass result;
CHECK_RESULT(_vkCreateRenderPass(dev, &rp_info, NULL, &result));
CHECK_RESULT(_vkCreateRenderPass(dev, &rp_info, nullptr, &result));
g_renderpass_cache[renderpass_key] = result;
return result;

View File

@@ -157,6 +157,9 @@ namespace vk
}
else if (elem_size == 4)
{
if(is_ror8)
shuffle_kernel = vk::get_compute_task<vk::cs_shuffle_ror8>();
else
shuffle_kernel = vk::get_compute_task<vk::cs_shuffle_32>();
}
else

View File

@@ -41,6 +41,7 @@ namespace vk
std::unique_ptr<vk::event> dma_fence;
vk::render_device* m_device = nullptr;
vk::viewable_image* vram_texture = nullptr;
bool is_ror8=false;
public:
using baseclass::cached_texture_section;
@@ -73,6 +74,9 @@ namespace vk
this->gcm_format = gcm_format;
this->pack_unpack_swap_bytes = pack_swap_bytes;
this->is_ror8=gcm_format==CELL_GCM_TEXTURE_A8R8G8B8||gcm_format==CELL_GCM_TEXTURE_D8R8G8B8;
if(g_cfg.video.bgra_format)this->is_ror8=false;
if (managed)
{
managed_texture.reset(vram_texture);

View File

@@ -10,6 +10,15 @@
#define DEF_VK_FUNCTION
#include "VKPFNTable.h"
#undef DEF_VK_FUNCTION
#if 0
#define VK_FUNC(func) PFN_##func _##func
#define INSTANCE_VK_FUNCTION
#define DEVICE_VK_FUNCTION
#include "VKPFNTableEXT.h"
#undef INSTANCE_VK_FUNCTION
#undef DEVICE_VK_FUNCTION
#undef VK_FUNC
#endif
namespace vk
{
@@ -56,19 +65,23 @@ namespace vk
void init_instance_pfn(VkInstance instance){
#if 1
#define INSTANCE_VK_FUNCTION
#define VK_FUNC(func) _##func = reinterpret_cast<PFN_##func>(_vkGetInstanceProcAddr(instance, #func))
#include "VKPFNTableEXT.h"
#undef INSTANCE_VK_FUNCTION
#undef VK_FUNC
#endif
}
void init_device_pfn(VkDevice device){
#if 1
#define DEVICE_VK_FUNCTION
#define VK_FUNC(func) _##func = reinterpret_cast<PFN_##func>(_vkGetDeviceProcAddr(device, #func))
#include "VKPFNTableEXT.h"
#undef DEVICE_VK_FUNCTION
#undef VK_FUNC
#endif
}
}

View File

@@ -34,6 +34,15 @@ extern bool cfg_vertex_buffer_upload_mode_use_buffer_view();
#include "VKPFNTable.h"
#undef DECL_VK_FUNCTION
#if 0
#define VK_FUNC(func) extern PFN_##func _##func
#define INSTANCE_VK_FUNCTION
#define DEVICE_VK_FUNCTION
#include "VKPFNTableEXT.h"
#undef INSTANCE_VK_FUNCTION
#undef DEVICE_VK_FUNCTION
#undef VK_FUNC
#endif
namespace vk
{
void init_base_pfn();

View File

@@ -185,7 +185,7 @@ namespace vk
CHECK_RESULT(_vkCreateBuffer(m_device, &info, nullptr, &value));
auto& memory_map = dev.get_memory_mapping();
ensure(_vkGetMemoryHostPointerPropertiesEXT);
//ensure(_vkGetMemoryHostPointerPropertiesEXT);
VkMemoryHostPointerPropertiesEXT memory_properties{};
memory_properties.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT;

View File

@@ -96,7 +96,7 @@ namespace vk
}
//auto _vkGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(_vkGetInstanceProcAddr(parent, "_vkGetPhysicalDeviceFeatures2KHR"));
ensure(_vkGetPhysicalDeviceFeatures2KHR); // "_vkGetInstanceProcAddress failed to find entry point!"
//ensure(_vkGetPhysicalDeviceFeatures2KHR); // "_vkGetInstanceProcAddress failed to find entry point!"
_vkGetPhysicalDeviceFeatures2KHR(dev, &features2);
shader_types_support.allow_float64 = !!features2.features.shaderFloat64;
@@ -217,7 +217,7 @@ namespace vk
}
//auto _vkGetPhysicalDeviceProperties2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(_vkGetInstanceProcAddr(parent, "_vkGetPhysicalDeviceProperties2KHR"));
ensure(_vkGetPhysicalDeviceProperties2KHR);
//ensure(_vkGetPhysicalDeviceProperties2KHR);
_vkGetPhysicalDeviceProperties2KHR(dev, &properties2);
props = properties2.properties;

View File

@@ -75,7 +75,7 @@ namespace vk
dbgCreateInfo.pfnCallback = callback;
dbgCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
CHECK_RESULT(_vkCreateDebugReportCallbackEXT(m_instance, &dbgCreateInfo, NULL, &m_debugger));
CHECK_RESULT(_vkCreateDebugReportCallbackEXT(m_instance, &dbgCreateInfo, nullptr, &m_debugger));
}
#ifdef __clang__

View File

@@ -17,7 +17,7 @@ namespace vk
return "Extended fault info is not available. Extension 'VK_EXT_device_fault' is probably not supported by your driver.";
}
ensure(_vkGetDeviceFaultInfoEXT);
//ensure(_vkGetDeviceFaultInfoEXT);
VkDeviceFaultCountsEXT fault_counts
{

View File

@@ -18,7 +18,7 @@ namespace vk
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.window =reinterpret_cast<ANativeWindow *>(window_handle);
CHECK_RESULT(_vkCreateAndroidSurfaceKHR(vk_instance, &createInfo, NULL, &result));
CHECK_RESULT(_vkCreateAndroidSurfaceKHR(vk_instance, &createInfo, nullptr, &result));
return result;
}
#endif

View File

@@ -14,7 +14,6 @@
#include "vksym.h"
#undef VKFN
#endif
namespace {
void* lib_handle = nullptr;
}

View File

@@ -1,3 +1,4 @@
#if 1
VKFN(vkAcquireNextImageKHR);
VKFN(vkAllocateCommandBuffers);
VKFN(vkAllocateDescriptorSets);
@@ -155,4 +156,5 @@ VKFN(vkSetDebugUtilsObjectNameEXT);
VKFN(vkSetEvent);
VKFN(vkUnmapMemory);
VKFN(vkUpdateDescriptorSets);
VKFN(vkWaitForFences);
VKFN(vkWaitForFences);
#endif

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: WTFPL
package aenu.aps3e;
import android.app.Activity;
@@ -146,6 +147,10 @@ public class AboutActivity extends AppCompatActivity {
+ " *修复了方向键和摇杆\n"
+ " *可为游戏创建单独的配置\n"
+ " *增加些调试功能\n"
+ "1.25(2025-06-30)\n"
+ " *虚拟键盘更新,增加动态摇杆,可设置组缩放\n"
+ " *增加了按键震动\n"
+ " *更改ffmpeg版本为5.1.6\n"
+ " \n";
return log;

View File

@@ -24,6 +24,8 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
private SparseIntArray keysMap = new SparseIntArray();
private GameFrameView gv;
private Vibrator vibrator=null;
private VibrationEffect vibrationEffect=null;
boolean started=false;
void setup_env(String serial){
@@ -33,8 +35,8 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
boolean enable_log=getSharedPreferences("debug",MODE_PRIVATE).getBoolean("enable_log",false);
aenu.lang.System.setenv("APS3E_ENABLE_LOG",Boolean.toString(enable_log));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -51,8 +53,8 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
gv.setOnGenericMotionListener(this);
gv.getHolder().addCallback(this);
load_key_map();
load_key_map_and_vibrator();
Emulator.MetaInfo meta_info = (Emulator.MetaInfo) getIntent().getSerializableExtra("meta_info");
setup_env(meta_info.serial);
/*if(meta_info==null){
@@ -133,6 +135,7 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
int gameKey = keysMap.get(keyCode, 0);
if (gameKey == 0) return super.onKeyDown(keyCode, event);
if (event.getRepeatCount() == 0){
vibrator();
Emulator.get.key_event(gameKey, true);
return true;
}
@@ -164,10 +167,13 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
if (Float.compare(xaxis, -1.0f) == 0) {
Emulator.get.key_event(ControlId.l, true);
Emulator.get.key_event(ControlId.r, false);
vibrator();
pressed=true;
} else if (Float.compare(xaxis, 1.0f) == 0) {
Emulator.get.key_event(ControlId.r, true);
Emulator.get.key_event(ControlId.l, false);
vibrator();
pressed=true;
}
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
@@ -175,10 +181,14 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
if (Float.compare(yaxis, -1.0f) == 0) {
Emulator.get.key_event(ControlId.u, true);
Emulator.get.key_event(ControlId.d, false);
vibrator();
pressed=true;
} else if (Float.compare(yaxis, 1.0f) == 0) {
Emulator.get.key_event(ControlId.d, true);
Emulator.get.key_event(ControlId.u, false);
vibrator();
pressed=true;
}
}
@@ -189,21 +199,29 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
Emulator.get.key_event(ControlId.l, true);
Emulator.get.key_event(ControlId.r, false);
vibrator();
pressed=true;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
Emulator.get.key_event(ControlId.r, true);
Emulator.get.key_event(ControlId.l, false);
vibrator();
pressed=true;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
Emulator.get.key_event(ControlId.u, true);
Emulator.get.key_event(ControlId.d, false);
vibrator();
pressed=true;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
Emulator.get.key_event(ControlId.d, true);
Emulator.get.key_event(ControlId.u, false);
vibrator();
pressed=true;
}
@@ -307,9 +325,13 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
return super.onGenericMotionEvent(event);
}
void vibrator(){
if(vibrator!=null) {
vibrator.vibrate(vibrationEffect);
}
}
void load_key_map() {
void load_key_map_and_vibrator() {
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(this);
keysMap.clear();
for (int i = 0; i < KeyMapConfig.KEY_NAMEIDS.length; i++) {
@@ -317,6 +339,10 @@ public class EmulatorActivity extends Activity implements View.OnGenericMotionLi
int keyCode = sPrefs.getInt(keyName, KeyMapConfig.DEFAULT_KEYMAPPERS[i]);
keysMap.put(keyCode, KeyMapConfig.KEY_VALUES[i]);
}
if(sPrefs.getBoolean("enable_vibrator",false)){
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrationEffect = VibrationEffect.createOneShot(25, VibrationEffect.DEFAULT_AMPLITUDE);
}
}
@Override

View File

@@ -33,24 +33,46 @@ import android.view.*;
import androidx.appcompat.app.AppCompatActivity;
import aenu.view.SVListView;
public class KeyMapActivity extends AppCompatActivity {
SharedPreferences sp;
ListView lv;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
sp=getSharedPreferences();
lv=new ListView(this);
lv.setDividerHeight(32);
setContentView(lv);
update_config();
lv.setOnItemClickListener(click_l);
setContentView(R.layout.activity_keymap);
((SVListView)findViewById(R.id.keymap_list)).setOnItemClickListener(click_l);
((Button)findViewById(R.id.keymap_reset)).setOnClickListener(reset_l);
((CheckBox)findViewById(R.id.enable_vibrator)).setChecked(sp.getBoolean("enable_vibrator",false));
((CheckBox)findViewById(R.id.enable_vibrator)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sp.edit().putBoolean("enable_vibrator",isChecked).commit();
}
});
/*
final String vibrator_duration_hiht=getString(R.string.vibrator_duration)+": ";
((TextView)findViewById(R.id.vibrator_duration_label)).setText(vibrator_duration_hiht+sp.getInt("vibrator_duration",25));
((SeekBar)findViewById(R.id.vibrator_duration)).setProgress(sp.getInt("vibrator_duration",25));
((SeekBar)findViewById(R.id.vibrator_duration)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
((TextView)findViewById(R.id.vibrator_duration_label)).setText(vibrator_duration_hiht+progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});*/
refresh_view();
}
void refresh_view(){
lv.setAdapter(new KeyListAdapter(this,KeyMapConfig.KEY_NAMEIDS,get_all_key_mapper_values()));
((SVListView)findViewById(R.id.keymap_list)).setAdapter(new KeyListAdapter(this,KeyMapConfig.KEY_NAMEIDS,get_all_key_mapper_values()));
}
void update_config(){
@@ -116,6 +138,19 @@ public class KeyMapActivity extends AppCompatActivity {
}
};
private final View.OnClickListener reset_l=new View.OnClickListener(){
@Override
public void onClick(View v)
{
for(int i=0;i<KeyMapConfig.KEY_NAMEIDS.length;i++){
String key_n=Integer.toString(KeyMapConfig.KEY_NAMEIDS[i]);
int default_v=KeyMapConfig.DEFAULT_KEYMAPPERS[i];
sp.edit().putInt(key_n,default_v).commit();
}
refresh_view();
}
};
private SharedPreferences getSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(this);
}
@@ -160,7 +195,7 @@ public class KeyMapActivity extends AppCompatActivity {
if(curView==null){
curView=new TextView(context_);
curView=new TextView(context_,null,androidx.appcompat.R.attr.textAppearanceListItem);
}
TextView text=(TextView)curView;

View File

@@ -17,26 +17,26 @@ public class KeyMapConfig {
};
public static final int[] KEY_NAMEIDS = new int[]{
R.string.keymapper_l,
R.string.keymapper_u,
R.string.keymapper_r,
R.string.keymapper_d,
R.string.keymapper_square,
R.string.keymapper_cross,
R.string.keymapper_circle,
R.string.keymapper_triangle,
R.string.left,
R.string.up,
R.string.right,
R.string.down,
R.string.square,
R.string.cross,
R.string.circle,
R.string.triangle,
R.string.keymapper_l1,
R.string.keymapper_l2,
R.string.keymapper_l3,
R.string.l1,
R.string.l2,
R.string.l3,
R.string.keymapper_r1,
R.string.keymapper_r2,
R.string.keymapper_r3,
R.string.r1,
R.string.r2,
R.string.r3,
R.string.keymapper_start,
R.string.keymapper_select,
R.string.keymapper_ps,
R.string.start,
R.string.select,
R.string.ps,
};
public static final int[] KEY_VALUES = new int[]{

View File

@@ -148,7 +148,7 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
getSupportActionBar().setTitle(getString(R.string.select_game));//"选择游戏");
android.util.Log.e("aps3e_java","main");
android.util.Log.i("aps3e_java","main");
setContentView(R.layout.activity_main);

View File

@@ -6,6 +6,7 @@ import android.os.*;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.TextView;
import android.window.OnBackInvokedDispatcher;
@@ -72,27 +73,122 @@ public class VirtualPadEdit extends Activity
});
final String scale_text=getString(R.string.scale_rate)+": ";
float scale=iv.getScale();
float joystick_scale=iv.getScale(InputOverlay.ScaleType.JOYSTICK);
float dpad_scale=iv.getScale(InputOverlay.ScaleType.DPAD);
float abxy_scale=iv.getScale(InputOverlay.ScaleType.ABXY);
float ss_scale=iv.getScale(InputOverlay.ScaleType.START_SELECT);
float lr_scale=iv.getScale(InputOverlay.ScaleType.LR);
float ps_scale=iv.getScale(InputOverlay.ScaleType.PS);
((TextView)d.findViewById(R.id.virtual_pad_scale_hint)).setText(scale_text+scale);
((SeekBar)d.findViewById(R.id.virtual_pad_scale)).setProgress((int)(scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
((TextView)d.findViewById(R.id.virtual_pad_joystick_scale_hint)).setText(scale_text+joystick_scale);
((TextView)d.findViewById(R.id.virtual_pad_dpad_scale_hint)).setText(scale_text+dpad_scale);
((TextView)d.findViewById(R.id.virtual_pad_button_scale_hint)).setText(scale_text+abxy_scale);
((TextView)d.findViewById(R.id.virtual_pad_ss_scale_hint)).setText(scale_text+ss_scale);
((TextView)d.findViewById(R.id.virtual_pad_lr_scale_hint)).setText(scale_text+lr_scale);
((TextView)d.findViewById(R.id.virtual_pad_ps_scale_hint)).setText(scale_text+ps_scale);
((SeekBar)d.findViewById(R.id.virtual_pad_joystick_scale)).setProgress((int)(joystick_scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_joystick_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
float scale;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
scale=progress/100.f;
((TextView)d.findViewById(R.id.virtual_pad_scale_hint)).setText(scale_text+scale);
((TextView)d.findViewById(R.id.virtual_pad_joystick_scale_hint)).setText(scale_text+scale);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {iv.setScale(InputOverlay.ScaleType.JOYSTICK,scale);}
});
((SeekBar)d.findViewById(R.id.virtual_pad_dpad_scale)).setProgress((int)(dpad_scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_dpad_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
float scale;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
scale=progress/100.f;
((TextView)d.findViewById(R.id.virtual_pad_dpad_scale_hint)).setText(scale_text+scale);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
iv.setScale(scale);
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {iv.setScale(InputOverlay.ScaleType.DPAD,scale);}
});
((SeekBar)d.findViewById(R.id.virtual_pad_button_scale)).setProgress((int)(abxy_scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_button_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
float scale;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
scale=progress/100.f;
((TextView)d.findViewById(R.id.virtual_pad_button_scale_hint)).setText(scale_text+scale);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {iv.setScale(InputOverlay.ScaleType.ABXY,scale);}
});
((SeekBar)d.findViewById(R.id.virtual_pad_ss_scale)).setProgress((int)(ss_scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_ss_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
float scale;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
scale=progress/100.f;
((TextView)d.findViewById(R.id.virtual_pad_ss_scale_hint)).setText(scale_text+scale);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {iv.setScale(InputOverlay.ScaleType.START_SELECT,scale);}
});
((SeekBar)d.findViewById(R.id.virtual_pad_lr_scale)).setProgress((int)(lr_scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_lr_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
float scale;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
scale=progress/100.f;
((TextView)d.findViewById(R.id.virtual_pad_lr_scale_hint)).setText(scale_text+scale);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {iv.setScale(InputOverlay.ScaleType.LR,scale);}
});
((SeekBar)d.findViewById(R.id.virtual_pad_ps_scale)).setProgress((int)(ps_scale*100));
((SeekBar)d.findViewById(R.id.virtual_pad_ps_scale)).setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
float scale;
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
scale=progress/100.f;
((TextView)d.findViewById(R.id.virtual_pad_ps_scale_hint)).setText(scale_text+scale);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {iv.setScale(InputOverlay.ScaleType.PS,scale);}
});
final int[] dynamic_joysticks={
R.id.virtual_pad_dynamic_joystick_disable,
R.id.virtual_pad_dynamic_joystick_use_left,
R.id.virtual_pad_dynamic_joystick_use_right
};
//get_dynamic_joystick return -1 0 1
((RadioGroup)d.findViewById(R.id.virtual_pad_dynamic_joystick))
.check(dynamic_joysticks[iv.get_dynamic_joystick()+1]);
((RadioGroup)d.findViewById(R.id.virtual_pad_dynamic_joystick)).setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int dynamic_joystick;
for(int i=0;i<dynamic_joysticks.length;i++){
if(dynamic_joysticks[i]==checkedId){
iv.set_dynamic_joystick(i-1);
return;
}
}
}
});

View File

@@ -0,0 +1,17 @@
package aenu.view;
import android.widget.ListView;
public class SVListView extends ListView {
public SVListView(android.content.Context context, android.util.AttributeSet attrs) {
super(context, attrs);
}
public SVListView(android.content.Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}

View File

@@ -59,8 +59,33 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
private InputOverlayDrawableButton mButtonBeingConfigured;
private InputOverlayDrawableDpad mDpadBeingConfigured;
private InputOverlayDrawableJoystick mJoystickBeingConfigured;
private static float mGlobalScale = 1.0f;
//private static float mGlobalScale = 1.0f;
private static float m_dpad_scale = 1.0f;
private static float m_joystick_scale = 1.0f;
private static float m_abxy_scale = 1.0f;
private static float m_lr_scale = 1.0f;
private static float m_ss_scale = 1.0f;
private static float m_ps_scale = 1.0f;
private static int mGlobalOpacity = 100;
private static int m_dynamic_joystick = -1;
private static boolean m_dynamic_joystick_pressed = false;
private static boolean m_left_joystick_enabled = true;
private static boolean m_right_joystick_enabled = true;
private static boolean m_dpad_enabled = true;
private static boolean m_square_enabled = true;
private static boolean m_triangle_enabled = true;
private static boolean m_circle_enabled = true;
private static boolean m_cross_enabled = true;
private static boolean m_start_enabled = true;
private static boolean m_select_enabled = true;
private static boolean m_l1_enabled = true;
private static boolean m_l2_enabled = true;
private static boolean m_l3_enabled = true;
private static boolean m_r1_enabled = true;
private static boolean m_r2_enabled = true;
private static boolean m_r3_enabled = true;
private static boolean m_ps_enabled = true;
private Timer mTimer;
@@ -205,10 +230,73 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
if(joystick.getXControl() !=m_dynamic_joystick||m_dynamic_joystick_pressed)
joystick.draw(canvas);
}
}
void handle_left_joystick_event(float x, float y){
if(x!=0){
if(x<0){
Emulator.get.key_event(ControlId.lsr,false);
Emulator.get.key_event(ControlId.lsl,true,(int)Math.abs(x*255.0));
}
else{
Emulator.get.key_event(ControlId.lsl,false);
Emulator.get.key_event(ControlId.lsr,true,(int)Math.abs(x*255.0));
}
}
else{
Emulator.get.key_event(ControlId.lsr,false);
Emulator.get.key_event(ControlId.lsl,false);
}
if(y!=0){
if(y<0){
Emulator.get.key_event(ControlId.lsd,false);
Emulator.get.key_event(ControlId.lsu,true,(int)Math.abs(y*255.0));
}else{
Emulator.get.key_event(ControlId.lsu,false);
Emulator.get.key_event(ControlId.lsd,true,(int)Math.abs(y*255.0));
}
}
else{
Emulator.get.key_event(ControlId.lsd,false);
Emulator.get.key_event(ControlId.lsu,false);
}
}
void handle_right_joystick_event(float x, float y){
if(x!=0){
if(x<0){
Emulator.get.key_event(ControlId.rsr,false);
Emulator.get.key_event(ControlId.rsl,true,(int)Math.abs(x*255.0));
}else{
Emulator.get.key_event(ControlId.rsl,false);
Emulator.get.key_event(ControlId.rsr,true,(int)Math.abs(x*255.0));
}
}
else{
Emulator.get.key_event(ControlId.rsr,false);
Emulator.get.key_event(ControlId.rsl,false);
}
if(y!=0){
if(y<0){
Emulator.get.key_event(ControlId.rsd,false);
Emulator.get.key_event(ControlId.rsu,true,(int)Math.abs(y*255.0));
}else{
Emulator.get.key_event(ControlId.rsu,false);
Emulator.get.key_event(ControlId.rsd,true,(int)Math.abs(y*255.0));
}
}
else{
Emulator.get.key_event(ControlId.rsd,false);
Emulator.get.key_event(ControlId.rsu,false);
}
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
@@ -228,6 +316,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
int pointerIndex = firstPointer ? 0 : event.getActionIndex();
// track if the overlay is concerned this this action
boolean concerned = false;
boolean skip_dynamic_joystick_pressed = false;
for (InputOverlayDrawableButton button : overlayButtons)
{
@@ -246,6 +335,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
button.setPressedState(true);
button.setTrackId(event.getPointerId(pointerIndex));
concerned = true;
skip_dynamic_joystick_pressed = true;
/*if(button.getRole() == OVERLAY_MASK_TOUCH_SCREEN_SWITCH)
setTouchState(button.getPressed());
else*/
@@ -280,6 +370,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
.contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex)))
{
dpad.setTrackId(event.getPointerId(pointerIndex));
skip_dynamic_joystick_pressed = true;
concerned = true;
}
case MotionEvent.ACTION_MOVE:
@@ -311,6 +402,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
{
if (dpadPressed[i])
{
skip_dynamic_joystick_pressed = true;
Emulator.get.key_event(dpad.getControl(i), true);
}
else{
@@ -339,83 +431,79 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
if (joystick.TrackEvent(event))
int control=joystick.getXControl();
if (joystick.TrackEvent(event)&&control!=m_dynamic_joystick)
{
concerned = true;
skip_dynamic_joystick_pressed = true;
/*int joyX = Math.round(joystick.getX() * (1 << 15));
joyX = Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, joyX));
int joyY = Math.round(joystick.getY() * (1 << 15));
joyY = Math.max(Short.MIN_VALUE, Math.min(Short.MAX_VALUE, joyY));*/
int control=joystick.getXControl();
//左摇杆
if(control==0){
float x=joystick.getX();
float y=joystick.getY();
if(x!=0){
if(x<0){
Emulator.get.key_event(ControlId.lsr,false);
Emulator.get.key_event(ControlId.lsl,true,(int)Math.abs(x*255.0));
}
else{
Emulator.get.key_event(ControlId.lsl,false);
Emulator.get.key_event(ControlId.lsr,true,(int)Math.abs(x*255.0));
}
}
else{
Emulator.get.key_event(ControlId.lsr,false);
Emulator.get.key_event(ControlId.lsl,false);
}
if(y!=0){
if(y<0){
Emulator.get.key_event(ControlId.lsd,false);
Emulator.get.key_event(ControlId.lsu,true,(int)Math.abs(y*255.0));
}else{
Emulator.get.key_event(ControlId.lsu,false);
Emulator.get.key_event(ControlId.lsd,true,(int)Math.abs(y*255.0));
}
}
else{
Emulator.get.key_event(ControlId.lsd,false);
Emulator.get.key_event(ControlId.lsu,false);
}
handle_left_joystick_event(x,y);
}
//右摇杆
else if(control==1){
float x=joystick.getX();
float y=joystick.getY();
if(x!=0){
if(joystick.getX()<0){
Emulator.get.key_event(ControlId.rsr,false);
Emulator.get.key_event(ControlId.rsl,true,(int)Math.abs(x*255.0));
}else{
Emulator.get.key_event(ControlId.rsl,false);
Emulator.get.key_event(ControlId.rsr,true,(int)Math.abs(x*255.0));
}
}
else{
Emulator.get.key_event(ControlId.rsr,false);
Emulator.get.key_event(ControlId.rsl,false);
}
handle_right_joystick_event(x,y);
}
}
}
if(y!=0){
if(joystick.getY()<0){
Emulator.get.key_event(ControlId.rsd,false);
Emulator.get.key_event(ControlId.rsu,true,(int)Math.abs(y*255.0));
}else{
Emulator.get.key_event(ControlId.rsu,false);
Emulator.get.key_event(ControlId.rsd,true,(int)Math.abs(y*255.0));
}
}
else{
Emulator.get.key_event(ControlId.rsd,false);
Emulator.get.key_event(ControlId.rsu,false);
}
}
}
//动态摇杆
{
InputOverlayDrawableJoystick dynamic_joystick=null;
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
if(joystick.getXControl()==m_dynamic_joystick)
dynamic_joystick=joystick;
if(dynamic_joystick!=null){
if(!skip_dynamic_joystick_pressed&&(action==MotionEvent.ACTION_DOWN||action==MotionEvent.ACTION_POINTER_DOWN)){
int touchX = (int)event.getX(pointerIndex);
int touchY = (int)event.getY(pointerIndex);
int w=dynamic_joystick.getWidth();
int h=dynamic_joystick.getHeight();
int l=touchX-(w>>1);
int t=touchY-(h>>1);
int r=l+w;
int d=t+h;
dynamic_joystick.updateBounds(l,t,r,d);
dynamic_joystick.setPosition(l,t);
}
if (dynamic_joystick.TrackEvent(event)){
concerned=true;
m_dynamic_joystick_pressed=true;
if(m_dynamic_joystick==0)
handle_left_joystick_event(dynamic_joystick.getX(),dynamic_joystick.getY());
else if(m_dynamic_joystick==1)
handle_right_joystick_event(dynamic_joystick.getX(),dynamic_joystick.getY());
}
else{
if(m_dynamic_joystick_pressed){
if(m_dynamic_joystick==0)
handle_left_joystick_event(0,0);
else if(m_dynamic_joystick==1)
handle_right_joystick_event(0,0);
concerned=true;
}
m_dynamic_joystick_pressed=false;
}
}
}
if(concerned)
@@ -518,6 +606,9 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
{
if(joystick.getXControl()==m_dynamic_joystick)
continue;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
@@ -596,56 +687,95 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
mGlobalScale=sPrefs.getFloat("mGlobalScale",1.0f);
//mGlobalScale=sPrefs.getFloat("mGlobalScale",1.0f);
m_dynamic_joystick=sPrefs.getInt("m_dynamic_joystick",-1);
m_joystick_scale=sPrefs.getFloat("m_joystick_scale",1.0f);
m_dpad_scale=sPrefs.getFloat("m_dpad_scale",1.0f);
m_abxy_scale=sPrefs.getFloat("m_abxy_scale",1.0f);
m_lr_scale=sPrefs.getFloat("m_lr_scale",1.0f);
m_ss_scale=sPrefs.getFloat("m_ss_scale",1.0f);
m_ps_scale=sPrefs.getFloat("m_ps_scale",1.0f);
m_left_joystick_enabled=sPrefs.getBoolean("m_left_joystick_enabled",true);
m_right_joystick_enabled=sPrefs.getBoolean("m_right_joystick_enabled",true);
m_dpad_enabled=sPrefs.getBoolean("m_dpad_enabled",true);
m_square_enabled=sPrefs.getBoolean("m_square_enabled",true);
m_cross_enabled=sPrefs.getBoolean("m_cross_enabled",true);
m_triangle_enabled=sPrefs.getBoolean("m_triangle_enabled",true);
m_circle_enabled=sPrefs.getBoolean("m_circle_enabled",true);
m_start_enabled=sPrefs.getBoolean("m_start_enabled",true);
m_select_enabled=sPrefs.getBoolean("m_select_enabled",true);
m_l1_enabled=sPrefs.getBoolean("m_l1_enabled",true);
m_r1_enabled=sPrefs.getBoolean("m_r1_enabled",true);
m_l2_enabled=sPrefs.getBoolean("m_l2_enabled",true);
m_r2_enabled=sPrefs.getBoolean("m_r2_enabled",true);
m_l3_enabled=sPrefs.getBoolean("m_l3_enabled",true);
m_r3_enabled=sPrefs.getBoolean("m_r3_enabled",true);
m_ps_enabled=sPrefs.getBoolean("m_ps_enabled",true);
if(m_cross_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_cross,
R.drawable.button_cross_pressed, ButtonType.BUTTON_CROSS, ControlId.cross,
orientation, OVERLAY_MASK_BASIC));
if(m_circle_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_circle,
R.drawable.button_circle_pressed, ButtonType.BUTTON_CIRCLE, ControlId.circle,
orientation, OVERLAY_MASK_BASIC));
if(m_square_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_square,
R.drawable.button_square_pressed, ButtonType.BUTTON_SQUARE, ControlId.square,
orientation, OVERLAY_MASK_BASIC));
if(m_triangle_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_triangle,
R.drawable.button_triangle_pressed, ButtonType.BUTTON_TRIANGLE, ControlId.triangle,
orientation, OVERLAY_MASK_BASIC));
if(m_start_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_start,
R.drawable.button_start_pressed, ButtonType.BUTTON_START,
ControlId.start, orientation, OVERLAY_MASK_BASIC));
if(m_select_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_select,
R.drawable.button_select_pressed, ButtonType.BUTTON_SELECT,
ControlId.select, orientation, OVERLAY_MASK_BASIC));
if(m_l1_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_l,
R.drawable.button_l_pressed, ButtonType.TRIGGER_L,
ControlId.l1, orientation, OVERLAY_MASK_BASIC));
if(m_r1_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_r,
R.drawable.button_r_pressed, ButtonType.TRIGGER_R,
ControlId.r1, orientation, OVERLAY_MASK_BASIC));
if(m_l2_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_l2,
R.drawable.button_l2_pressed, ButtonType.TRIGGER_L2,
ControlId.l2, orientation, OVERLAY_MASK_BASIC));
if(m_r2_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_r2,
R.drawable.button_r2_pressed, ButtonType.TRIGGER_R2,
ControlId.r2, orientation, OVERLAY_MASK_BASIC));
if(m_l3_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_l3,
R.drawable.button_l3_pressed, ButtonType.TRIGGER_L3,
ControlId.l3, orientation, OVERLAY_MASK_BASIC));
if(m_r3_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.button_r3,
R.drawable.button_r3_pressed, ButtonType.TRIGGER_R3,
ControlId.r3, orientation, OVERLAY_MASK_BASIC));
if(m_ps_enabled)
overlayButtons.add(initializeOverlayButton(getContext(), R.drawable.app_icon,
R.drawable.app_icon, ButtonType.BUTTON_PS,
ControlId.ps, orientation, OVERLAY_MASK_BASIC));
@@ -655,17 +785,20 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
R.drawable.button_touch_b, ButtonType.BUTTON_TOUCH_SWITCH,
ControlId.touch, orientation, OVERLAY_MASK_TOUCH_SCREEN_SWITCH));
*/
if(m_dpad_enabled)
overlayDpads.add(initializeOverlayDpad(getContext(), R.drawable.dpad_idle,
R.drawable.dpad_up,
R.drawable.dpad_up_left,
ButtonType.DPAD_UP, ControlId.u, ControlId.d,
ControlId.l, ControlId.r, orientation));
if(m_left_joystick_enabled)
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.joystick_range,
R.drawable.joystick, R.drawable.joystick_pressed,
ButtonType.STICK_LEFT, 0,0,/*ControlId.axis_left_x,
ControlId.axis_left_y,*/ orientation));
if(m_right_joystick_enabled)
overlayJoysticks.add(initializeOverlayJoystick(getContext(), R.drawable.joystick_range,
R.drawable.joystick, R.drawable.joystick_pressed,
ButtonType.STICK_RIGHT, 1,1,/*ControlId.axis_right_x,
@@ -691,6 +824,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
vitaDefaultOverlay();
refreshControls();
}
/*
public float getScale(){
return mGlobalScale;
}
@@ -703,6 +837,73 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
sPrefsEditor.commit();
refreshControls();
}
}*/
public float getScale(int scale_type){
switch(scale_type){
case ScaleType.JOYSTICK:
return m_joystick_scale;
case ScaleType.DPAD:
return m_dpad_scale;
case ScaleType.ABXY:
return m_abxy_scale;
case ScaleType.START_SELECT:
return m_ss_scale;
case ScaleType.LR:
return m_lr_scale;
case ScaleType.PS:
return m_ps_scale;
}
throw new IllegalArgumentException("Invalid scale type");
}
public void setScale(int scale_type,float scale){
switch (scale_type){
case ScaleType.JOYSTICK:
m_joystick_scale = scale;
break;
case ScaleType.DPAD:
m_dpad_scale = scale;
break;
case ScaleType.ABXY:
m_abxy_scale = scale;
break;
case ScaleType.START_SELECT:
m_ss_scale = scale;
break;
case ScaleType.LR:
m_lr_scale = scale;
break;
case ScaleType.PS:
m_ps_scale = scale;
}
{
SharedPreferences.Editor sPrefsEditor = mPreferences.edit();
sPrefsEditor.putFloat("m_joystick_scale",m_joystick_scale);
sPrefsEditor.putFloat("m_dpad_scale",m_dpad_scale);
sPrefsEditor.putFloat("m_abxy_scale",m_abxy_scale);
sPrefsEditor.putFloat("m_ss_scale",m_ss_scale);
sPrefsEditor.putFloat("m_lr_scale",m_lr_scale);
sPrefsEditor.putFloat("m_ps_scale",m_ps_scale);
sPrefsEditor.commit();
refreshControls();
}
}
//-1 disabled
//0 left joystick
//1 right joystick
public void set_dynamic_joystick(int dynamic_joystick){
m_dynamic_joystick = dynamic_joystick;
SharedPreferences.Editor sPrefsEditor = mPreferences.edit();
sPrefsEditor.putInt("m_dynamic_joystick",m_dynamic_joystick);
sPrefsEditor.commit();
refreshControls();
}
public int get_dynamic_joystick(){
return m_dynamic_joystick;
}
public void setOpacity(int opacity){
@@ -778,21 +979,22 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(context);
// Decide scale based on button ID and user preference
float scale = 0.15f;
float scale = 0.15f*m_abxy_scale;
if(legacyId == ButtonType.TRIGGER_L
|| legacyId == ButtonType.TRIGGER_R
|| legacyId == ButtonType.TRIGGER_L2
|| legacyId == ButtonType.TRIGGER_R2
|| legacyId == ButtonType.TRIGGER_L3
|| legacyId == ButtonType.TRIGGER_R3
|| legacyId == ButtonType.BUTTON_START
|| legacyId == ButtonType.TRIGGER_R3)
scale = 0.20f*m_lr_scale;
else if(legacyId == ButtonType.BUTTON_START
|| legacyId == ButtonType.BUTTON_SELECT)
scale = 0.20f;
scale = 0.20f*m_ss_scale;
else if(legacyId == ButtonType.BUTTON_PS)
scale = 0.06f;
scale = 0.06f*m_ps_scale;
scale *= mGlobalScale;
//scale *= mGlobalScale;
// Initialize the InputOverlayDrawableButton.
final Bitmap defaultStateBitmap =
@@ -856,7 +1058,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Decide scale based on button ID and user preference
float scale = 0.35f;
scale *= mGlobalScale;
scale *= m_dpad_scale;
// Initialize the InputOverlayDrawableDpad.
final Bitmap defaultStateBitmap =
@@ -915,7 +1117,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Decide scale based on user preference
float scale = 0.275f;
scale *= mGlobalScale;
scale *= m_joystick_scale;
// Initialize the InputOverlayDrawableJoystick.
final Bitmap bitmapOuter =
@@ -1081,6 +1283,15 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
r1,r2,r3,
start,select,
};*/
public static final class ScaleType {
public static final int JOYSTICK = 0;
public static final int DPAD = 1;
public static final int ABXY = 2;
public static final int START_SELECT = 3;
public static final int LR = 4;
public static final int PS = 5;
}
public static final class ButtonType
{
public static final int BUTTON_CROSS = 0;

View File

@@ -278,6 +278,15 @@ public final class InputOverlayDrawableJoystick
mOuterBitmap.setBounds(bounds);
}
public void updateBounds(int left, int top, int right, int bottom)
{
mOuterBitmap.setBounds(left, top, right, bottom);
mVirtBounds = getBounds();
mOrigBounds = mOuterBitmap.copyBounds();
mBoundsBoxBitmap.setBounds(getVirtBounds());
SetInnerBounds();
}
public void setOpacity(int value)
{
mOpacity = value;

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/list_navigation">
<ImageButton
android:id="@+id/goto_parent_dir"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_goto_parent_dir"
android:layout_alignParentRight="true"
android:maxHeight="32dip"/>
<EditText
android:textAppearance="?android:attr/textAppearanceMedium"
android:id="@+id/list_path_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/goto_parent_dir"
android:singleLine="true"
android:layout_centerInParent="true"/>
</RelativeLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:id="@+id/list_view"
android:orientation="vertical"
android:fastScrollEnabled="true"/>
</LinearLayout>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<aenu.view.SVListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/keymap_list"/>
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/enable_vibrator"
android:id="@+id/enable_vibrator"/>
<!--LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/vibrator_duration_label"/>
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="25"
android:id="@+id/vibrator_duration"/>
</LinearLayout-->
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/keymap_reset"
android:text="@string/reset_as_default"/>
</LinearLayout>
</ScrollView>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingRight="1dip"
android:paddingLeft="1dip"
android:paddingTop="1dip"
android:paddingBottom="1dip"
android:gravity="center_vertical">
<ImageView
android:id="@+id/file_icon"
android:layout_width="56dip"
android:layout_height="32dip"
android:layout_marginLeft="5dip"
android:layout_marginRight="1dip"
android:layout_gravity="center_vertical"
android:layout_centerInParent="true"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?android:attr/textAppearanceMedium"
android:id="@+id/file_tag"/>
</LinearLayout>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingRight="1dip"
android:paddingLeft="1dip"
android:paddingTop="1dip"
android:paddingBottom="1dip"
android:gravity="center_vertical">
<ImageView
android:id="@android:id/icon"
android:layout_width="56dip"
android:layout_height="32dip"
android:layout_marginLeft="5dip"
android:layout_marginRight="1dip"
android:layout_gravity="center_vertical"
android:layout_centerInParent="true"
android:layout_alignParentLeft="true"/>
<include
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="@android:layout/simple_list_item_2"
android:layout_gravity="center"/>
</LinearLayout>

View File

@@ -1,25 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--摇杆-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/joystick"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/virtual_pad_scale_hint" />
android:id="@+id/virtual_pad_joystick_scale_hint" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:min="20"
android:max="300"
android:progress="100"
android:id="@+id/virtual_pad_scale" />
</LinearLayout>
android:id="@+id/virtual_pad_joystick_scale" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/dynamic_joystick"/>
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/virtual_pad_dynamic_joystick">
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/disable"
android:id="@+id/virtual_pad_dynamic_joystick_disable"
android:checked="true"/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/left"
android:id="@+id/virtual_pad_dynamic_joystick_use_left"/>
<RadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/right"
android:id="@+id/virtual_pad_dynamic_joystick_use_right"/>
</RadioGroup>
<!--方向键-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/dpad"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/virtual_pad_dpad_scale_hint" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:min="20"
android:max="300"
android:progress="100"
android:id="@+id/virtual_pad_dpad_scale" />
<!--ABXY-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/button"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/virtual_pad_button_scale_hint" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:min="20"
android:max="300"
android:progress="100"
android:id="@+id/virtual_pad_button_scale" />
<!--开始/选择-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/start_select"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/virtual_pad_ss_scale_hint" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:min="20"
android:max="300"
android:progress="100"
android:id="@+id/virtual_pad_ss_scale" />
<!--LR-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/lr"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/virtual_pad_lr_scale_hint" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:min="20"
android:max="300"
android:progress="100"
android:id="@+id/virtual_pad_lr_scale" />
<!--PS-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/ps"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="@+id/virtual_pad_ps_scale_hint" />
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:min="20"
android:max="300"
android:progress="100"
android:id="@+id/virtual_pad_ps_scale" />
<Button
android:id="@+id/virtual_pad_reset"
@@ -32,4 +168,6 @@
android:layout_height="wrap_content"
android:text="@string/save_and_quit" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/pad_no_use_lb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="空"
android:enabled="false"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:visibility="invisible"/>
<Button
android:id="@+id/pad_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/pad_no_use_lb"/>
<Button
android:id="@+id/pad_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="左"
android:layout_above="@id/pad_no_use_lb"
android:layout_alignParentLeft="true"
android:layout_marginBottom="2dp"/>
<Button
android:id="@+id/pad_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="右"
android:layout_above="@id/pad_down"
android:layout_toRightOf="@id/pad_down"
android:layout_marginLeft="2dp"/>
<Button
android:id="@+id/pad_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上"
android:layout_above="@id/pad_left"
android:layout_toRightOf="@id/pad_no_use_lb"
android:layout_marginBottom="2dp"/>
<Button
android:id="@+id/pad_no_use_rb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="空"
android:enabled="false"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:visibility="invisible"/>
<Button
android:id="@+id/button_x"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="X"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/pad_no_use_rb"/>
<Button
android:id="@+id/button_o"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="O"
android:layout_above="@id/button_x"
android:layout_toRightOf="@id/button_x"
android:layout_alignParentRight="true"
android:layout_marginBottom="2dp"/>
<Button
android:id="@+id/button_square"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="口"
android:layout_above="@id/button_x"
android:layout_toLeftOf="@id/button_x"
android:layout_marginBottom="2dp"/>
<Button
android:id="@+id/button_triangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="△"
android:layout_above="@id/button_o"
android:layout_toLeftOf="@id/pad_no_use_rb"
android:layout_marginBottom="2dp"/>
<Button
android:id="@+id/button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"/>
<Button
android:id="@+id/button_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/button_start"
android:layout_marginLeft="2dp"/>
</RelativeLayout>

View File

@@ -1,6 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
</LinearLayout>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView android:id="@+id/value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"/>
<SeekBar android:id="@+id/seekbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dip"/>
</LinearLayout>

View File

@@ -6,6 +6,17 @@
<string name="emulator_settings_video_vulkan_debug">调试</string>
<string name="vibrator_duration">震动时长</string>
<string name="enable_vibrator">启用震动</string>
<string name="dynamic_joystick">动态摇杆</string>
<string name="disable">禁用</string>
<string name="joystick">摇杆</string>
<string name="dpad">方向键</string>
<string name="button">按钮</string>
<string name="lr">LR</string>
<string name="start_select">开始/选择</string>
<string name="enable_log">启用日志</string>
<string name="use_global_config">使用全局配置</string>
<string name="edit_custom_config">编辑自定义配置</string>
@@ -54,38 +65,27 @@
<string name="key_mappers">按键映射</string>
<string name="virtual_pad_edit">虚拟键盘编辑</string>
<string name="keymapper_l"></string>
<string name="keymapper_u"></string>
<string name="keymapper_r"></string>
<string name="keymapper_d"></string>
<string name="left"></string>
<string name="up"></string>
<string name="right"></string>
<string name="down"></string>
<string name="keymapper_square">方框</string>
<string name="keymapper_cross"></string>
<string name="keymapper_circle"></string>
<string name="keymapper_triangle">三角</string>
<string name="square">方框</string>
<string name="cross"></string>
<string name="circle"></string>
<string name="triangle">三角</string>
<string name="keymapper_lsl">左(左摇杆)</string>
<string name="keymapper_lsu">上(左摇杆)</string>
<string name="keymapper_lsr">右(左摇杆)</string>
<string name="keymapper_lsd">下(左摇杆)</string>
<string name="l1">L1</string>
<string name="l2">L2</string>
<string name="l3">L3</string>
<string name="keymapper_rsl">左(右摇杆)</string>
<string name="keymapper_rsu">上(右摇杆)</string>
<string name="keymapper_rsr">右(右摇杆)</string>
<string name="keymapper_rsd">下(右摇杆)</string>
<string name="keymapper_l1">L1</string>
<string name="keymapper_l2">L2</string>
<string name="keymapper_l3">L3</string>
<string name="keymapper_r1">R1</string>
<string name="keymapper_r2">R2</string>
<string name="keymapper_r3">R3</string>
<string name="keymapper_start">开始</string>
<string name="keymapper_select">选择</string>
<string name="keymapper_ps">PS</string>
<string name="r1">R1</string>
<string name="r2">R2</string>
<string name="r3">R3</string>
<string name="start">开始</string>
<string name="select">选择</string>
<string name="ps">PS</string>
<string name="emulator_settings_video_vulkan_custom_driver_library_path_dialog_title">选择一个自定义驱动</string>
<string name="emulator_settings_video_vulkan_custom_driver_library_path_dialog_add_hint">添加自定义驱动(*.zip, *.so)</string>

View File

@@ -8,6 +8,17 @@
<string name="emulator_settings_video_vulkan_debug">Debug</string>
<string name="vibrator_duration">Virbrator Duration</string>
<string name="enable_vibrator">Enable Vibrator</string>
<string name="dynamic_joystick">Dynamic Joystick</string>
<string name="disable">Disable</string>
<string name="joystick">Joystick</string>
<string name="dpad">Dpad</string>
<string name="button">Button</string>
<string name="lr">LR</string>
<string name="start_select">Start/Select</string>
<string name="enable_log">Enable Log</string>
<string name="use_global_config">Use Global Config</string>
<string name="edit_custom_config">Edit Custom Config</string>
@@ -55,37 +66,27 @@
<string name="key_mappers">Key Mappers</string>
<string name="virtual_pad_edit">VirtualPadEdit</string>
<string name="keymapper_l">left</string>
<string name="keymapper_u">up</string>
<string name="keymapper_r">right</string>
<string name="keymapper_d">down</string>
<string name="left">left</string>
<string name="up">up</string>
<string name="right">right</string>
<string name="down">down</string>
<string name="keymapper_square">square</string>
<string name="keymapper_cross">cross</string>
<string name="keymapper_circle">circle</string>
<string name="keymapper_triangle">triangle</string>
<string name="keymapper_lsl">left (Left joystick)</string>
<string name="keymapper_lsu">up (Left joystick)</string>
<string name="keymapper_lsr">right (Left joystick)</string>
<string name="keymapper_lsd">down (Left joystick)</string>
<string name="keymapper_rsl">left (Right joystick)</string>
<string name="keymapper_rsu">up (Right joystick)</string>
<string name="keymapper_rsr">right (Right joystick)</string>
<string name="keymapper_rsd">down (Right joystick)</string>
<string name="square">square</string>
<string name="cross">cross</string>
<string name="circle">circle</string>
<string name="triangle">triangle</string>
<string name="keymapper_l1">L1</string>
<string name="keymapper_l2">L2</string>
<string name="keymapper_l3">L3</string>
<string name="l1">L1</string>
<string name="l2">L2</string>
<string name="l3">L3</string>
<string name="keymapper_r1">R1</string>
<string name="keymapper_r2">R2</string>
<string name="keymapper_r3">R3</string>
<string name="r1">R1</string>
<string name="r2">R2</string>
<string name="r3">R3</string>
<string name="keymapper_start">start</string>
<string name="keymapper_select">select</string>
<string name="keymapper_ps">PS</string>
<string name="start">start</string>
<string name="select">select</string>
<string name="ps">PS</string>
<string name="emulator_settings_video_vulkan_custom_driver_library_path_dialog_title">Select a Custom Driver</string>