mirror of
https://github.com/BillyOutlast/aps3e.git
synced 2026-02-04 03:01:22 +01:00
25
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "GLDMA.h"
|
||||
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/RSX/GL/glutils/common.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "../Program/FragmentProgramDecompiler.h"
|
||||
#include "../Program/GLSLTypes.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
|
||||
namespace glsl
|
||||
|
||||
@@ -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 = ®S(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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "GLPipelineCompiler.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "util/sysinfo.hpp"
|
||||
|
||||
namespace gl
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "../Program/VertexProgramDecompiler.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include "../glutils/fbo.h"
|
||||
#include "../glutils/image.h"
|
||||
#include "../glutils/state_tracker.hpp"
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "vksym.h"
|
||||
#undef VKFN
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
void* lib_handle = nullptr;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[]{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
17
app/src/main/java/aenu/view/SVListView.java
Normal file
17
app/src/main/java/aenu/view/SVListView.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
43
app/src/main/res/layout/activity_keymap.xml
Normal file
43
app/src/main/res/layout/activity_keymap.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user