fixed random crashes

improved nv0039::buffer_notify
added print_call_stack utility (TODO)
This commit is contained in:
DHrpcs3 2016-03-13 14:21:45 +03:00
parent 8aeac09741
commit 10ec26ace8
7 changed files with 159 additions and 99 deletions

View file

@ -441,7 +441,7 @@ void GLGSRender::end()
int location;
if (m_program->uniforms.has_location("tex" + std::to_string(i), &location))
{
__glcheck rsx::gl_texture::bind(m_texture_cache, textures[i]);
__glcheck rsx::gl_texture::bind(texture_cache, textures[i]);
__glcheck glProgramUniform1i(m_program->id(), location, i);
}
}
@ -708,7 +708,7 @@ void GLGSRender::end()
rsx::thread::end();
m_texture_cache.update_protection();
texture_cache.update_protection();
}
void GLGSRender::set_viewport()
@ -829,7 +829,7 @@ void GLGSRender::on_exit()
}
}
void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
bool nv4097_clear_surface(u32 arg, GLGSRender* renderer)
{
//LOG_NOTICE(RSX, "nv4097_clear_surface(0x%x)", arg);
@ -844,7 +844,7 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
if ((arg & (depth_stencil | color_mask)) == 0)
{
//do nothing
return;
return true;
}
/*
@ -941,13 +941,22 @@ void nv4097_clear_surface(u32 arg, GLGSRender* renderer)
{
__glcheck glClear(mask);
}
return true;
}
using rsx_method_impl_t = void(*)(u32, GLGSRender*);
bool nv3089_image_in(u32 arg, GLGSRender* renderer)
{
//TODO
return false;
}
using rsx_method_impl_t = bool(*)(u32, GLGSRender*);
static const std::unordered_map<u32, rsx_method_impl_t> g_gl_method_tbl =
{
{ NV4097_CLEAR_SURFACE, nv4097_clear_surface }
{ NV4097_CLEAR_SURFACE, nv4097_clear_surface },
//{ NV3089_IMAGE_IN, nv3089_image_in },
};
bool GLGSRender::do_method(u32 cmd, u32 arg)
@ -959,8 +968,7 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
return false;
}
found->second(arg, this);
return true;
return found->second(arg, this);
}
bool GLGSRender::load_program()
@ -1205,7 +1213,7 @@ void GLGSRender::init_buffers(bool skip_reading)
info.swizzled = swizzled;
cached_color_buffers[index] = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
cached_color_buffers[index] = &texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
draw_fbo.color[index] = cached_color_buffers[index]->view();
});
@ -1269,7 +1277,7 @@ void GLGSRender::init_buffers(bool skip_reading)
info.format.remap = { GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO };
__glcheck cached_depth_buffer = &m_texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
__glcheck cached_depth_buffer = &texture_cache.entry(info, skip_reading ? gl::cache_buffers::none : gl::cache_buffers::local);
switch (m_surface.depth_format)
{
@ -1333,7 +1341,7 @@ void GLGSRender::flip(int buffer)
glDisable(GL_LOGIC_OP);
glDisable(GL_CULL_FACE);
gl::cached_texture& texture = m_texture_cache.entry(surface_info(rsx::surface_color_format::a8r8g8b8, gcm_buffers[buffer].offset,
gl::cached_texture& texture = texture_cache.entry(surface_info(rsx::surface_color_format::a8r8g8b8, gcm_buffers[buffer].offset,
CELL_GCM_LOCATION_LOCAL, buffer_width, buffer_height, buffer_pitch), gl::cache_buffers::local);
//std::lock_guard<gl::cached_texture> lock(texture);
@ -1389,7 +1397,7 @@ u64 GLGSRender::timestamp() const
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
{
if (auto region = m_texture_cache.find_region(address))
if (auto region = texture_cache.find_region(address))
{
//std::lock_guard<gl::protected_region> lock(*region);

View file

@ -28,9 +28,8 @@ private:
texture_buffer_pair m_gl_attrib_buffers[rsx::limits::vertex_count];
gl::texture_cache m_texture_cache;
public:
gl::texture_cache texture_cache;
gl::fbo draw_fbo;
private:

View file

@ -1,6 +1,42 @@
#include "stdafx.h"
#include "gl_helpers.h"
#ifdef _WIN32
#include <DbgHelp.h>
#pragma comment(lib, "Dbghelp.lib")
#endif
//TODO: find proper place
void print_call_stack(int skip)
{
#ifdef _WIN32
HANDLE current_process = GetCurrentProcess();
SymInitialize(current_process, nullptr, true);
void* stack[61];
u32 frames_count = CaptureStackBackTrace(skip + 1, 61 - skip, stack, nullptr);
u32 max_sym_length = 255;
std::unique_ptr<SYMBOL_INFO, decltype(&std::free)> sym_info
{
(SYMBOL_INFO*)std::calloc(sizeof(SYMBOL_INFO) + (max_sym_length + 1) * sizeof(char), 1),
std::free
};
sym_info->MaxNameLen = max_sym_length;
sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
LOG_ERROR(GENERAL, "CALL STACK:");
for (s32 i = frames_count - 1; i > 0; --i)
{
SymFromAddr(current_process, (DWORD64)stack[i], 0, sym_info.get());
LOG_ERROR(GENERAL, "%u: %s:%u - 0x%0X", i, sym_info->Name, sym_info->Index, sym_info->Address);
}
#endif
}
namespace gl
{
const fbo screen{};

View file

@ -13,6 +13,8 @@
#include "OpenGL.h"
#include "../GCM.h"
void print_call_stack(int skip);
namespace gl
{
#if 1//def _DEBUG
@ -44,6 +46,7 @@ namespace gl
default: error = "unknown error"; break;
}
print_call_stack(1);
throw std::runtime_error(fmt::format("OpenGL error: %s. file '%s' function '%s' line %ld", error.c_str(), file, function, line));
}
}

View file

@ -18,19 +18,19 @@ namespace gl
void cached_texture::read()
{
cached_texture* found_texture = nullptr;
u32 texture_size = info->size();
u32 texture_size = info.size();
m_parent_region->for_each(info->start_address, texture_size, [&](cached_texture& texture)
m_parent_region->for_each(info.start_address, texture_size, [&](cached_texture& texture)
{
if ((texture.m_state & cache_entry_state::local_synchronized) == cache_entry_state::invalid)
{
return;
}
if (texture.info->start_address != info->start_address ||
texture.info->pitch != info->pitch ||
texture.info->height < info->height ||
texture.info->width < info->width)
if (texture.info.start_address != info.start_address ||
texture.info.pitch != info.pitch ||
texture.info.height < info.height ||
texture.info.width < info.width)
{
return;
}
@ -42,35 +42,35 @@ namespace gl
{
//read from local
__glcheck glCopyImageSubData(
found_texture->gl_name, (GLenum)found_texture->info->target, 0, 0, 0, 0,
gl_name, (GLenum)info->target, 0, 0, 0, 0,
info->width, info->height, info->depth);
found_texture->gl_name, (GLenum)found_texture->info.target, 0, 0, 0, 0,
gl_name, (GLenum)info.target, 0, 0, 0, 0,
info.width, info.height, info.depth);
}
else
{
//read from host
//flush all local textures at region
m_parent_region->for_each(info->start_address, texture_size, [](cached_texture& texture)
m_parent_region->for_each(info.start_address, texture_size, [](cached_texture& texture)
{
texture.sync(gl::cache_buffers::host);
});
bind();
if (info->format.format == gl::texture::format::depth || info->format.format == gl::texture::format::depth_stencil)
if (info.format.format == gl::texture::format::depth || info.format.format == gl::texture::format::depth_stencil)
{
gl::buffer pbo_depth;
__glcheck pbo_depth.create(info->size());
__glcheck pbo_depth.create(info.size());
__glcheck pbo_depth.map([&](GLubyte* pixels)
{
switch (info->format.bpp)
switch (info.format.bpp)
{
case 2:
{
u16 *dst = (u16*)pixels;
const be_t<u16>* src = (const be_t<u16>*)vm::base_priv(info->start_address);
for (u32 i = 0, end = info->pitch / info->format.bpp * info->height; i < end; ++i)
const be_t<u16>* src = (const be_t<u16>*)vm::base_priv(info.start_address);
for (u32 i = 0, end = info.pitch / info.format.bpp * info.height; i < end; ++i)
{
dst[i] = src[i];
}
@ -80,8 +80,8 @@ namespace gl
case 4:
{
u32 *dst = (u32*)pixels;
const be_t<u32>* src = (const be_t<u32>*)vm::base_priv(info->start_address);
for (u32 i = 0, end = info->pitch / info->format.bpp * info->height; i < end; ++i)
const be_t<u32>* src = (const be_t<u32>*)vm::base_priv(info.start_address);
for (u32 i = 0, end = info.pitch / info.format.bpp * info.height; i < end; ++i)
{
dst[i] = src[i];
}
@ -94,47 +94,47 @@ namespace gl
}, gl::buffer::access::write);
gl::pixel_unpack_settings{}
.row_length(info->pitch / info->format.bpp)
.row_length(info.pitch / info.format.bpp)
.aligment(1)
.swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
//.swap_bytes((info.format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
.apply();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_depth.id());
__glcheck glTexSubImage2D((GLenum)info->target, 0, 0, 0, info->width, info->height,
(GLenum)info->format.format, (GLenum)info->format.type, nullptr);
__glcheck glTexSubImage2D((GLenum)info.target, 0, 0, 0, info.width, info.height,
(GLenum)info.format.format, (GLenum)info.format.type, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
else if (info->compressed_size)
else if (info.compressed_size)
{
__glcheck glCompressedTexSubImage2D((GLenum)info->target, 0,
0, 0, info->width, info->height,
(GLenum)info->format.internal_format,
info->compressed_size, vm::base_priv(info->start_address));
__glcheck glCompressedTexSubImage2D((GLenum)info.target, 0,
0, 0, info.width, info.height,
(GLenum)info.format.internal_format,
info.compressed_size, vm::base_priv(info.start_address));
}
else
{
void *pixels = vm::base_priv(info->start_address);
void *pixels = vm::base_priv(info.start_address);
std::unique_ptr<u8[]> linear_pixels;
if (info->swizzled && (info->format.flags & texture_flags::allow_swizzle) != texture_flags::none)
if (info.swizzled && (info.format.flags & texture_flags::allow_swizzle) != texture_flags::none)
{
linear_pixels.reset(new u8[info->size()]);
switch (info->format.bpp)
linear_pixels.reset(new u8[info.size()]);
switch (info.format.bpp)
{
case 1:
rsx::convert_linear_swizzle<u8>(pixels, linear_pixels.get(), info->width, info->height, true);
rsx::convert_linear_swizzle<u8>(pixels, linear_pixels.get(), info.width, info.height, true);
break;
case 2:
rsx::convert_linear_swizzle<u16>(pixels, linear_pixels.get(), info->width, info->height, true);
rsx::convert_linear_swizzle<u16>(pixels, linear_pixels.get(), info.width, info.height, true);
break;
case 4:
rsx::convert_linear_swizzle<u32>(pixels, linear_pixels.get(), info->width, info->height, true);
rsx::convert_linear_swizzle<u32>(pixels, linear_pixels.get(), info.width, info.height, true);
break;
case 8:
rsx::convert_linear_swizzle<u64>(pixels, linear_pixels.get(), info->width, info->height, true);
rsx::convert_linear_swizzle<u64>(pixels, linear_pixels.get(), info.width, info.height, true);
break;
default:
@ -145,22 +145,22 @@ namespace gl
}
gl::pixel_unpack_settings{}
.row_length(info->pitch / info->format.bpp)
.row_length(info.pitch / info.format.bpp)
.aligment(1)
.swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
.swap_bytes((info.format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
.apply();
__glcheck glTexSubImage2D((GLenum)info->target, 0, 0, 0, info->width, info->height,
(GLenum)info->format.format, (GLenum)info->format.type, pixels);
__glcheck glTexSubImage2D((GLenum)info.target, 0, 0, 0, info.width, info.height,
(GLenum)info.format.format, (GLenum)info.format.type, pixels);
}
if (info->mipmap > 1)
if (info.mipmap > 1)
{
__glcheck glTexParameteri((GLenum)info->target, GL_TEXTURE_MIN_LOD, info->min_lod);
__glcheck glTexParameteri((GLenum)info->target, GL_TEXTURE_MAX_LOD, info->max_lod);
__glcheck glTexParameterf((GLenum)info->target, GL_TEXTURE_LOD_BIAS, info->lod_bias);
__glcheck glTexParameteri((GLenum)info.target, GL_TEXTURE_MIN_LOD, info.min_lod);
__glcheck glTexParameteri((GLenum)info.target, GL_TEXTURE_MAX_LOD, info.max_lod);
__glcheck glTexParameterf((GLenum)info.target, GL_TEXTURE_LOD_BIAS, info.lod_bias);
__glcheck glGenerateMipmap((GLenum)info->target);
__glcheck glGenerateMipmap((GLenum)info.target);
}
}
@ -171,33 +171,33 @@ namespace gl
{
bind();
if (info->format.format == gl::texture::format::depth || info->format.format == gl::texture::format::depth_stencil)
if (info.format.format == gl::texture::format::depth || info.format.format == gl::texture::format::depth_stencil)
{
//LOG_ERROR(RSX, "write depth color to host[0x%x]", info->start_address);
//LOG_ERROR(RSX, "write depth color to host[0x%x]", info.start_address);
gl::buffer pbo_depth;
pbo_depth.create(info->size());
pbo_depth.create(info.size());
gl::pixel_pack_settings{}
.row_length(info->pitch / info->format.bpp)
.row_length(info.pitch / info.format.bpp)
.aligment(1)
//.swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
//.swap_bytes((info.format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
.apply();
__glcheck glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_depth.id());
__glcheck glGetTexImage((GLenum)info->target, 0, (GLenum)info->format.format, (GLenum)info->format.type, nullptr);
__glcheck glGetTexImage((GLenum)info.target, 0, (GLenum)info.format.format, (GLenum)info.format.type, nullptr);
__glcheck glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
__glcheck pbo_depth.map([&](GLubyte* pixels)
{
switch (info->format.bpp)
switch (info.format.bpp)
{
case 2:
{
const u16 *src = (const u16*)pixels;
be_t<u16>* dst = (be_t<u16>*)vm::base_priv(info->start_address);
for (u32 i = 0, end = info->pitch / info->format.bpp * info->height; i < end; ++i)
be_t<u16>* dst = (be_t<u16>*)vm::base_priv(info.start_address);
for (u32 i = 0, end = info.pitch / info.format.bpp * info.height; i < end; ++i)
{
dst[i] = src[i];
}
@ -207,8 +207,8 @@ namespace gl
case 4:
{
const u32 *src = (const u32*)pixels;
be_t<u32>* dst = (be_t<u32>*)vm::base_priv(info->start_address);
for (u32 i = 0, end = info->pitch / info->format.bpp * info->height; i < end; ++i)
be_t<u32>* dst = (be_t<u32>*)vm::base_priv(info.start_address);
for (u32 i = 0, end = info.pitch / info.format.bpp * info.height; i < end; ++i)
{
dst[i] = src[i];
}
@ -221,25 +221,25 @@ namespace gl
}, gl::buffer::access::read);
}
else if (info->compressed_size)
else if (info.compressed_size)
{
LOG_ERROR(RSX, "writing compressed texture[0x%x] to host buffer", info->start_address);
LOG_ERROR(RSX, "writing compressed texture[0x%x] to host buffer", info.start_address);
}
else
{
if (info->swizzled && (info->format.flags & texture_flags::allow_swizzle) != texture_flags::none)
if (info.swizzled && (info.format.flags & texture_flags::allow_swizzle) != texture_flags::none)
{
//TODO
LOG_ERROR(RSX, "writing swizzled texture[0x%x] to host buffer", info->start_address);
LOG_ERROR(RSX, "writing swizzled texture[0x%x] to host buffer", info.start_address);
}
gl::pixel_pack_settings{}
.row_length(info->pitch / info->format.bpp)
.row_length(info.pitch / info.format.bpp)
.aligment(1)
.swap_bytes((info->format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
.swap_bytes((info.format.flags & gl::texture_flags::swap_bytes) != gl::texture_flags::none)
.apply();
__glcheck glGetTexImage((GLenum)info->target, 0, (GLenum)info->format.format, (GLenum)info->format.type, vm::base_priv(info->start_address));
__glcheck glGetTexImage((GLenum)info.target, 0, (GLenum)info.format.format, (GLenum)info.format.type, vm::base_priv(info.start_address));
}
ignore(gl::cache_buffers::all);
@ -280,13 +280,13 @@ namespace gl
if ((buffers & cache_buffers::host) != cache_buffers::none)
{
m_state &= ~cache_entry_state::host_synchronized;
m_parent_region->for_each(info->start_address, info->size(), [this](cached_texture& texture)
m_parent_region->for_each(info.start_address, info.size(), [this](cached_texture& texture)
{
if (std::addressof(texture) != this)
{
//LOG_WARNING(RSX, "cached_texture[0x%x,0x%x) invalidate cached_texture[0x%x, 0x%x)",
// info->start_address, info->start_address + info->size(),
// texture.info->start_address, texture.info->start_address + texture.info->size());
// info.start_address, info.start_address + info.size(),
// texture.info.start_address, texture.info.start_address + texture.info.size());
texture.invalidate(cache_buffers::local);
}
});
@ -368,7 +368,7 @@ namespace gl
__glcheck glActiveTexture(GL_TEXTURE0 + index);
}
__glcheck glBindTexture((GLenum)info->target, gl_name);
__glcheck glBindTexture((GLenum)info.target, gl_name);
}
void cached_texture::create()
@ -378,8 +378,8 @@ namespace gl
glGenTextures(1, &gl_name);
bind();
__glcheck glTexStorage2D((GLenum)info->target, info->mipmap, (GLenum)info->format.internal_format, info->width, info->height);
//__glcheck glClearTexImage(gl_name, 0, (GLenum)info->format.format, (GLenum)info->format.type, nullptr);
__glcheck glTexStorage2D((GLenum)info.target, info.mipmap, (GLenum)info.format.internal_format, info.width, info.height);
//__glcheck glClearTexImage(gl_name, 0, (GLenum)info.format.format, (GLenum)info.format.type, nullptr);
}
void cached_texture::remove()
@ -528,7 +528,7 @@ namespace gl
auto& texture_info = *result.first;
texture_info.second.info = &texture_info.first;
texture_info.second.info = texture_info.first;
texture_info.second.parent(this);
return texture_info.second;

View file

@ -80,7 +80,7 @@ namespace gl
struct cached_texture
{
const texture_info *info;
texture_info info;
GLuint gl_name = 0;
private:
@ -103,7 +103,7 @@ namespace gl
gl::texture_view view() const
{
return{ info->target, gl_name };
return{ info.target, gl_name };
}
cache_access requires_protection() const;

View file

@ -604,31 +604,45 @@ namespace rsx
{
force_inline void buffer_notify(u32 arg)
{
const u32 inPitch = method_registers[NV0039_PITCH_IN];
const u32 outPitch = method_registers[NV0039_PITCH_OUT];
const u32 lineLength = method_registers[NV0039_LINE_LENGTH_IN];
const u32 lineCount = method_registers[NV0039_LINE_COUNT];
const u8 outFormat = method_registers[NV0039_FORMAT] >> 8;
const u8 inFormat = method_registers[NV0039_FORMAT];
u32 in_pitch = method_registers[NV0039_PITCH_IN];
u32 out_pitch = method_registers[NV0039_PITCH_OUT];
const u32 line_length = method_registers[NV0039_LINE_LENGTH_IN];
const u32 line_count = method_registers[NV0039_LINE_COUNT];
const u8 out_format = method_registers[NV0039_FORMAT] >> 8;
const u8 in_format = method_registers[NV0039_FORMAT];
const u32 notify = arg;
// The existing GCM commands use only the value 0x1 for inFormat and outFormat
if (inFormat != 0x01 || outFormat != 0x01)
if (in_format != 0x01 || out_format != 0x01)
{
LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", inFormat, outFormat);
LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", in_format, out_format);
}
if (lineCount == 1 && !inPitch && !outPitch && !notify)
if (!in_pitch)
{
std::memcpy(
vm::base(get_address(method_registers[NV0039_OFFSET_OUT], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT])),
vm::base(get_address(method_registers[NV0039_OFFSET_IN], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN])),
lineLength);
in_pitch = line_length;
}
if (!out_pitch)
{
out_pitch = line_length;
}
u8 *dst = (u8*)vm::base(get_address(method_registers[NV0039_OFFSET_OUT], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_OUT]));
const u8 *src = (u8*)vm::base(get_address(method_registers[NV0039_OFFSET_IN], method_registers[NV0039_SET_CONTEXT_DMA_BUFFER_IN]));
if (in_pitch == out_pitch && out_pitch == line_length)
{
std::memcpy(dst, src, line_length * line_count);
}
else
{
LOG_ERROR(RSX, "NV0039_OFFSET_IN: bad offset(in=0x%x, out=0x%x), pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
method_registers[NV0039_OFFSET_IN], method_registers[NV0039_OFFSET_OUT], inPitch, outPitch, lineLength, lineCount, inFormat, outFormat, notify);
for (u32 i = 0; i < line_count; ++i)
{
std::memcpy(dst, src, line_length);
dst += out_pitch;
src += in_pitch;
}
}
}
}