Moving common GL code out of gpu/.

This commit is contained in:
Ben Vanik
2015-07-01 07:29:14 -07:00
parent 5231e2e721
commit 0ebee76bfe
26 changed files with 185 additions and 204 deletions

View File

@@ -1,308 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/gl4/blitter.h"
#include <string>
#include "xenia/base/assert.h"
#include "xenia/base/math.h"
namespace xe {
namespace gpu {
namespace gl4 {
extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext();
Blitter::Blitter()
: vertex_program_(0),
color_fragment_program_(0),
depth_fragment_program_(0),
color_pipeline_(0),
depth_pipeline_(0),
vbo_(0),
vao_(0),
nearest_sampler_(0),
linear_sampler_(0),
scratch_framebuffer_(0) {}
Blitter::~Blitter() = default;
bool Blitter::Initialize() {
const std::string header =
"\n\
#version 450 \n\
#extension GL_ARB_explicit_uniform_location : require \n\
#extension GL_ARB_shading_language_420pack : require \n\
precision highp float; \n\
precision highp int; \n\
layout(std140, column_major) uniform; \n\
layout(std430, column_major) buffer; \n\
";
const std::string vs_source = header +
"\n\
layout(location = 0) uniform vec4 src_uv; \n\
out gl_PerVertex { \n\
vec4 gl_Position; \n\
float gl_PointSize; \n\
float gl_ClipDistance[]; \n\
}; \n\
layout(location = 0) in vec2 vfetch_pos; \n\
layout(location = 0) out vec2 vtx_uv; \n\
void main() { \n\
gl_Position = vec4(vfetch_pos.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0), 0.0, 1.0); \n\
vtx_uv = vfetch_pos.xy * src_uv.zw + src_uv.xy; \n\
} \n\
";
const std::string color_fs_source = header +
"\n\
layout(location = 1) uniform sampler2D src_texture; \n\
layout(location = 0) in vec2 vtx_uv; \n\
layout(location = 0) out vec4 oC; \n\
void main() { \n\
oC = texture(src_texture, vtx_uv); \n\
} \n\
";
const std::string depth_fs_source = header +
"\n\
layout(location = 1) uniform sampler2D src_texture; \n\
layout(location = 0) in vec2 vtx_uv; \n\
layout(location = 0) out vec4 oC; \n\
void main() { \n\
gl_FragDepth = texture(src_texture, vtx_uv).r; \n\
} \n\
";
auto vs_source_str = vs_source.c_str();
vertex_program_ = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vs_source_str);
auto color_fs_source_str = color_fs_source.c_str();
color_fragment_program_ =
glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &color_fs_source_str);
auto depth_fs_source_str = depth_fs_source.c_str();
depth_fragment_program_ =
glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &depth_fs_source_str);
glCreateProgramPipelines(1, &color_pipeline_);
glUseProgramStages(color_pipeline_, GL_VERTEX_SHADER_BIT, vertex_program_);
glUseProgramStages(color_pipeline_, GL_FRAGMENT_SHADER_BIT,
color_fragment_program_);
glCreateProgramPipelines(1, &depth_pipeline_);
glUseProgramStages(depth_pipeline_, GL_VERTEX_SHADER_BIT, vertex_program_);
glUseProgramStages(depth_pipeline_, GL_FRAGMENT_SHADER_BIT,
depth_fragment_program_);
glCreateBuffers(1, &vbo_);
static const GLfloat vbo_data[] = {
0, 0, 1, 0, 0, 1, 1, 1,
};
glNamedBufferStorage(vbo_, sizeof(vbo_data), vbo_data, 0);
glCreateVertexArrays(1, &vao_);
glEnableVertexArrayAttrib(vao_, 0);
glVertexArrayAttribBinding(vao_, 0, 0);
glVertexArrayAttribFormat(vao_, 0, 2, GL_FLOAT, GL_FALSE, 0);
glVertexArrayVertexBuffer(vao_, 0, vbo_, 0, sizeof(GLfloat) * 2);
glCreateSamplers(1, &nearest_sampler_);
glSamplerParameteri(nearest_sampler_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(nearest_sampler_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(nearest_sampler_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(nearest_sampler_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glCreateSamplers(1, &linear_sampler_);
glSamplerParameteri(linear_sampler_, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(linear_sampler_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(linear_sampler_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(linear_sampler_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glCreateFramebuffers(1, &scratch_framebuffer_);
return true;
}
void Blitter::Shutdown() {
glDeleteFramebuffers(1, &scratch_framebuffer_);
glDeleteProgram(vertex_program_);
glDeleteProgram(color_fragment_program_);
glDeleteProgram(depth_fragment_program_);
glDeleteProgramPipelines(1, &color_pipeline_);
glDeleteProgramPipelines(1, &depth_pipeline_);
glDeleteBuffers(1, &vbo_);
glDeleteVertexArrays(1, &vao_);
glDeleteSamplers(1, &nearest_sampler_);
glDeleteSamplers(1, &linear_sampler_);
}
struct SavedState {
GLboolean scissor_test_enabled;
GLboolean depth_test_enabled;
GLboolean depth_mask_enabled;
GLint depth_func;
GLboolean stencil_test_enabled;
GLboolean cull_face_enabled;
GLint cull_face;
GLint front_face;
GLint polygon_mode;
GLboolean color_mask_0_enabled[4];
GLboolean blend_0_enabled;
GLint draw_buffer;
GLfloat viewport[4];
GLint program_pipeline;
GLint vertex_array;
GLint texture_0;
GLint sampler_0;
void Save() {
scissor_test_enabled = glIsEnabled(GL_SCISSOR_TEST);
depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask_enabled);
glGetIntegerv(GL_DEPTH_FUNC, &depth_func);
stencil_test_enabled = glIsEnabled(GL_STENCIL_TEST);
cull_face_enabled = glIsEnabled(GL_CULL_FACE);
glGetIntegerv(GL_CULL_FACE_MODE, &cull_face);
glGetIntegerv(GL_FRONT_FACE, &front_face);
glGetIntegerv(GL_POLYGON_MODE, &polygon_mode);
glGetBooleani_v(GL_COLOR_WRITEMASK, 0, (GLboolean*)&color_mask_0_enabled);
blend_0_enabled = glIsEnabledi(GL_BLEND, 0);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_buffer);
glGetFloati_v(GL_VIEWPORT, 0, viewport);
glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &program_pipeline);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vertex_array);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture_0);
glGetIntegerv(GL_SAMPLER_BINDING, &sampler_0);
}
void Restore() {
scissor_test_enabled ? glEnable(GL_SCISSOR_TEST)
: glDisable(GL_SCISSOR_TEST);
depth_test_enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
glDepthMask(depth_mask_enabled);
glDepthFunc(depth_func);
stencil_test_enabled ? glEnable(GL_STENCIL_TEST)
: glDisable(GL_STENCIL_TEST);
cull_face_enabled ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE);
glCullFace(cull_face);
glFrontFace(front_face);
glPolygonMode(GL_FRONT_AND_BACK, polygon_mode);
glColorMaski(0, color_mask_0_enabled[0], color_mask_0_enabled[1],
color_mask_0_enabled[2], color_mask_0_enabled[3]);
blend_0_enabled ? glEnablei(GL_BLEND, 0) : glDisablei(GL_BLEND, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_buffer);
glViewportIndexedf(0, viewport[0], viewport[1], viewport[2], viewport[3]);
glBindProgramPipeline(program_pipeline);
glBindVertexArray(vertex_array);
glBindTexture(GL_TEXTURE_2D, texture_0);
glBindSampler(0, sampler_0);
}
};
void Blitter::Draw(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect,
GLenum filter) {
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
glDisablei(GL_BLEND, 0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBindVertexArray(vao_);
glBindTextures(0, 1, &src_texture);
switch (filter) {
default:
case GL_NEAREST:
glBindSampler(0, nearest_sampler_);
break;
case GL_LINEAR:
glBindSampler(0, linear_sampler_);
break;
}
glViewportIndexedf(0, GLfloat(dest_rect.x), GLfloat(dest_rect.y),
GLfloat(dest_rect.width), GLfloat(dest_rect.height));
// TODO(benvanik): avoid this?
GLint src_texture_width;
glGetTextureLevelParameteriv(src_texture, 0, GL_TEXTURE_WIDTH,
&src_texture_width);
GLint src_texture_height;
glGetTextureLevelParameteriv(src_texture, 0, GL_TEXTURE_HEIGHT,
&src_texture_height);
glProgramUniform4f(vertex_program_, 0, src_rect.x / float(src_texture_width),
src_rect.y / float(src_texture_height),
src_rect.width / float(src_texture_width),
src_rect.height / float(src_texture_height));
// Useful for seeing the entire framebuffer/etc:
// glProgramUniform4f(vertex_program_, 0, 0.0f, 0.0f, 1.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void Blitter::BlitTexture2D(GLuint src_texture, Rect2D src_rect,
Rect2D dest_rect, GLenum filter) {
SavedState state;
state.Save();
glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glStencilMask(0xFF);
glBindProgramPipeline(color_pipeline_);
Draw(src_texture, src_rect, dest_rect, filter);
state.Restore();
}
void Blitter::CopyColorTexture2D(GLuint src_texture, Rect2D src_rect,
GLuint dest_texture, Rect2D dest_rect,
GLenum filter) {
SavedState state;
state.Save();
glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glBindProgramPipeline(color_pipeline_);
glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0,
dest_texture, 0);
glNamedFramebufferDrawBuffer(scratch_framebuffer_, GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, scratch_framebuffer_);
Draw(src_texture, src_rect, dest_rect, filter);
glNamedFramebufferDrawBuffer(scratch_framebuffer_, GL_NONE);
glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0, GL_NONE,
0);
state.Restore();
}
void Blitter::CopyDepthTexture(GLuint src_texture, Rect2D src_rect,
GLuint dest_texture, Rect2D dest_rect) {
SavedState state;
state.Save();
glColorMaski(0, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glDepthMask(GL_TRUE);
glBindProgramPipeline(depth_pipeline_);
glNamedFramebufferTexture(scratch_framebuffer_, GL_DEPTH_STENCIL_ATTACHMENT,
dest_texture, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, scratch_framebuffer_);
Draw(src_texture, src_rect, dest_rect, GL_NEAREST);
glNamedFramebufferTexture(scratch_framebuffer_, GL_DEPTH_STENCIL_ATTACHMENT,
GL_NONE, 0);
state.Restore();
}
} // namespace gl4
} // namespace gpu
} // namespace xe

View File

@@ -1,70 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_BLITTER_H_
#define XENIA_GPU_GL4_BLITTER_H_
#include <memory>
#include "third_party/GL/glew.h"
#include "third_party/GL/wglew.h"
namespace xe {
namespace gpu {
namespace gl4 {
struct Rect2D {
int32_t x;
int32_t y;
int32_t width;
int32_t height;
Rect2D() : x(0), y(0), width(0), height(0) {}
Rect2D(int32_t x_, int32_t y_, int32_t width_, int32_t height_)
: x(x_), y(y_), width(width_), height(height_) {}
int32_t right() const { return x + width; }
int32_t bottom() const { return y + height; }
};
class Blitter {
public:
Blitter();
~Blitter();
bool Initialize();
void Shutdown();
void BlitTexture2D(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect,
GLenum filter);
void CopyColorTexture2D(GLuint src_texture, Rect2D src_rect,
GLuint dest_texture, Rect2D dest_rect, GLenum filter);
void CopyDepthTexture(GLuint src_texture, Rect2D src_rect,
GLuint dest_texture, Rect2D dest_rect);
private:
void Draw(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect,
GLenum filter);
GLuint vertex_program_;
GLuint color_fragment_program_;
GLuint depth_fragment_program_;
GLuint color_pipeline_;
GLuint depth_pipeline_;
GLuint vbo_;
GLuint vao_;
GLuint nearest_sampler_;
GLuint linear_sampler_;
GLuint scratch_framebuffer_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_BLITTER_H_

View File

@@ -1,151 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/gl4/circular_buffer.h"
#include "xenia/base/assert.h"
#include "xenia/base/math.h"
#include "xenia/gpu/gl4/gl4_gpu_flags.h"
#include "xenia/gpu/gpu_flags.h"
namespace xe {
namespace gpu {
namespace gl4 {
extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext();
CircularBuffer::CircularBuffer(size_t capacity, size_t alignment)
: capacity_(capacity),
alignment_(alignment),
write_head_(0),
dirty_start_(UINT64_MAX),
dirty_end_(0),
buffer_(0),
gpu_base_(0),
host_base_(nullptr) {}
CircularBuffer::~CircularBuffer() { Shutdown(); }
bool CircularBuffer::Initialize() {
glCreateBuffers(1, &buffer_);
glNamedBufferStorage(buffer_, capacity_, nullptr,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
host_base_ = reinterpret_cast<uint8_t*>(glMapNamedBufferRange(
buffer_, 0, capacity_,
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_PERSISTENT_BIT));
assert_not_null(host_base_);
if (!host_base_) {
return false;
}
if (FLAGS_vendor_gl_extensions && GLEW_NV_shader_buffer_load) {
// To use this bindlessly we must make it resident.
glMakeNamedBufferResidentNV(buffer_, GL_READ_ONLY);
glGetNamedBufferParameterui64vNV(buffer_, GL_BUFFER_GPU_ADDRESS_NV,
&gpu_base_);
}
return true;
}
void CircularBuffer::Shutdown() {
if (!buffer_) {
return;
}
glUnmapNamedBuffer(buffer_);
if (FLAGS_vendor_gl_extensions && GLEW_NV_shader_buffer_load) {
glMakeNamedBufferNonResidentNV(buffer_);
}
glDeleteBuffers(1, &buffer_);
buffer_ = 0;
}
bool CircularBuffer::CanAcquire(size_t length) {
size_t aligned_length = xe::round_up(length, alignment_);
return write_head_ + aligned_length <= capacity_;
}
CircularBuffer::Allocation CircularBuffer::Acquire(size_t length) {
// Addresses must always be % 256.
size_t aligned_length = xe::round_up(length, alignment_);
assert_true(aligned_length <= capacity_, "Request too large");
if (write_head_ + aligned_length > capacity_) {
// Flush and wait.
WaitUntilClean();
}
Allocation allocation;
allocation.host_ptr = host_base_ + write_head_;
allocation.gpu_ptr = gpu_base_ + write_head_;
allocation.offset = write_head_;
allocation.length = length;
allocation.aligned_length = aligned_length;
allocation.cache_key = 0;
write_head_ += aligned_length;
return allocation;
}
bool CircularBuffer::AcquireCached(uint32_t key, size_t length,
Allocation* out_allocation) {
uint64_t full_key = key | (length << 32);
auto& it = allocation_cache_.find(full_key);
if (it != allocation_cache_.end()) {
uintptr_t write_head = it->second;
size_t aligned_length = xe::round_up(length, alignment_);
out_allocation->host_ptr = host_base_ + write_head;
out_allocation->gpu_ptr = gpu_base_ + write_head;
out_allocation->offset = write_head;
out_allocation->length = length;
out_allocation->aligned_length = aligned_length;
out_allocation->cache_key = full_key;
return true;
} else {
*out_allocation = Acquire(length);
out_allocation->cache_key = full_key;
return false;
}
}
void CircularBuffer::Discard(Allocation allocation) {
write_head_ -= allocation.aligned_length;
}
void CircularBuffer::Commit(Allocation allocation) {
uintptr_t start = allocation.gpu_ptr - gpu_base_;
uintptr_t end = start + allocation.aligned_length;
dirty_start_ = std::min(dirty_start_, start);
dirty_end_ = std::max(dirty_end_, end);
assert_true(dirty_end_ <= capacity_);
if (allocation.cache_key) {
allocation_cache_.insert({allocation.cache_key, allocation.offset});
}
}
void CircularBuffer::Flush() {
if (dirty_start_ == dirty_end_ || dirty_start_ == UINT64_MAX) {
return;
}
glFlushMappedNamedBufferRange(buffer_, dirty_start_,
dirty_end_ - dirty_start_);
dirty_start_ = UINT64_MAX;
dirty_end_ = 0;
}
void CircularBuffer::ClearCache() { allocation_cache_.clear(); }
void CircularBuffer::WaitUntilClean() {
Flush();
glFinish();
write_head_ = 0;
ClearCache();
}
} // namespace gl4
} // namespace gpu
} // namespace xe

View File

@@ -1,71 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_CIRCULAR_BUFFER_H_
#define XENIA_GPU_GL4_CIRCULAR_BUFFER_H_
#include <unordered_map>
#include "xenia/gpu/gl4/gl_context.h"
namespace xe {
namespace gpu {
namespace gl4 {
// TODO(benvanik): uh, make this circular.
// TODO(benvanik): fences to prevent this from ever flushing.
class CircularBuffer {
public:
CircularBuffer(size_t capacity, size_t alignment = 256);
~CircularBuffer();
struct Allocation {
void* host_ptr;
GLuint64 gpu_ptr;
size_t offset;
size_t length;
size_t aligned_length;
uint64_t cache_key; // 0 if caching disabled.
};
bool Initialize();
void Shutdown();
GLuint handle() const { return buffer_; }
GLuint64 gpu_handle() const { return gpu_base_; }
size_t capacity() const { return capacity_; }
bool CanAcquire(size_t length);
Allocation Acquire(size_t length);
bool AcquireCached(uint32_t key, size_t length, Allocation* out_allocation);
void Discard(Allocation allocation);
void Commit(Allocation allocation);
void Flush();
void ClearCache();
void WaitUntilClean();
private:
size_t capacity_;
size_t alignment_;
uintptr_t write_head_;
uintptr_t dirty_start_;
uintptr_t dirty_end_;
GLuint buffer_;
GLuint64 gpu_base_;
uint8_t* host_base_;
std::unordered_map<uint64_t, uintptr_t> allocation_cache_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_CIRCULAR_BUFFER_H_

View File

@@ -30,8 +30,6 @@ namespace gl4 {
using namespace xe::gpu::xenos;
extern "C" GLEWContext* glewGetContext();
const GLuint kAnyTarget = UINT_MAX;
// All uncached vertex/index data goes here. If it fills up we need to sync
@@ -85,7 +83,8 @@ CommandProcessor::CommandProcessor(GL4GraphicsSystem* graphics_system)
CommandProcessor::~CommandProcessor() { CloseHandle(write_ptr_index_event_); }
bool CommandProcessor::Initialize(std::unique_ptr<GLContext> context) {
bool CommandProcessor::Initialize(
std::unique_ptr<xe::ui::gl::GLContext> context) {
context_ = std::move(context);
worker_running_ = true;

View File

@@ -18,9 +18,7 @@
#include <unordered_map>
#include <vector>
#include "xenia/gpu/gl4/circular_buffer.h"
#include "xenia/gpu/gl4/draw_batcher.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/gl4/gl4_shader.h"
#include "xenia/gpu/gl4/gl4_shader_translator.h"
#include "xenia/gpu/gl4/texture_cache.h"
@@ -29,6 +27,8 @@
#include "xenia/gpu/xenos.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/memory.h"
#include "xenia/ui/gl/circular_buffer.h"
#include "xenia/ui/gl/gl_context.h"
namespace xe {
namespace kernel {
@@ -67,7 +67,7 @@ class CommandProcessor {
uint32_t counter() const { return counter_; }
void increment_counter() { counter_++; }
bool Initialize(std::unique_ptr<GLContext> context);
bool Initialize(std::unique_ptr<xe::ui::gl::GLContext> context);
void Shutdown();
void CallInThread(std::function<void()> fn);
@@ -238,7 +238,7 @@ class CommandProcessor {
std::atomic<bool> worker_running_;
kernel::object_ref<kernel::XHostThread> worker_thread_;
std::unique_ptr<GLContext> context_;
std::unique_ptr<xe::ui::gl::GLContext> context_;
SwapHandler swap_handler_;
std::queue<std::function<void()>> pending_fns_;
@@ -292,7 +292,7 @@ class CommandProcessor {
TextureCache texture_cache_;
DrawBatcher draw_batcher_;
CircularBuffer scratch_buffer_;
xe::ui::gl::CircularBuffer scratch_buffer_;
private:
bool SetShadowRegister(uint32_t& dest, uint32_t register_name);

View File

@@ -22,8 +22,6 @@ namespace gl4 {
using namespace xe::gpu::xenos;
extern "C" GLEWContext* glewGetContext();
const size_t kCommandBufferCapacity = 16 * (1024 * 1024);
const size_t kCommandBufferAlignment = 4;
const size_t kStateBufferCapacity = 64 * (1024 * 1024);

View File

@@ -10,16 +10,18 @@
#ifndef XENIA_GPU_GL4_GL4_STATE_DATA_BUILDER_H_
#define XENIA_GPU_GL4_GL4_STATE_DATA_BUILDER_H_
#include "xenia/gpu/gl4/circular_buffer.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/gl4/gl4_shader.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/gl/circular_buffer.h"
#include "xenia/ui/gl/gl_context.h"
namespace xe {
namespace gpu {
namespace gl4 {
using xe::ui::gl::CircularBuffer;
union float4 {
float v[4];
struct {

View File

@@ -9,18 +9,6 @@
#include "xenia/gpu/gl4/gl4_gpu_flags.h"
DEFINE_bool(thread_safe_gl, false,
"Only allow one GL context to be active at a time.");
DEFINE_bool(disable_gl_context_reset, false,
"Do not aggressively reset the GL context (helps with capture "
"programs such as OBS or FRAPS).");
DEFINE_bool(gl_debug, false, "Enable OpenGL debug validation layer.");
DEFINE_bool(gl_debug_output, false, "Dump ARB_debug_output to stderr.");
DEFINE_bool(gl_debug_output_synchronous, true,
"ARB_debug_output will synchronize to be thread safe.");
DEFINE_bool(vendor_gl_extensions, false,
"Enable vendor-specific (NV, AMD, etc) GL extensions.");

View File

@@ -12,13 +12,6 @@
#include <gflags/gflags.h>
DECLARE_bool(thread_safe_gl);
DECLARE_bool(disable_gl_context_reset);
DECLARE_bool(gl_debug);
DECLARE_bool(gl_debug_output);
DECLARE_bool(gl_debug_output_synchronous);
DECLARE_bool(vendor_gl_extensions);
DECLARE_bool(disable_framebuffer_readback);

View File

@@ -17,16 +17,14 @@
#include "xenia/cpu/processor.h"
#include "xenia/emulator.h"
#include "xenia/gpu/gl4/gl4_gpu_flags.h"
#include "xenia/gpu/gl4/gl4_profiler_display.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/tracing.h"
#include "xenia/ui/gl/gl_profiler_display.h"
namespace xe {
namespace gpu {
namespace gl4 {
extern "C" GLEWContext* glewGetContext();
void InitializeIfNeeded();
void CleanupOnShutdown();
@@ -65,12 +63,12 @@ X_STATUS GL4GraphicsSystem::Setup(cpu::Processor* processor,
// Create rendering control.
// This must happen on the UI thread.
xe::threading::Fence control_ready_fence;
std::unique_ptr<GLContext> processor_context;
std::unique_ptr<xe::ui::gl::GLContext> processor_context;
target_loop_->Post([&]() {
// Setup the GL control that actually does the drawing.
// We run here in the loop and only touch it (and its context) on this
// thread. That means some sync-fu when we want to swap.
control_ = std::make_unique<WGLControl>(target_loop_);
control_ = std::make_unique<xe::ui::gl::WGLControl>(target_loop_);
target_window_->AddChild(control_.get());
// Setup the GL context the command processor will do all its drawing in.
@@ -79,9 +77,9 @@ X_STATUS GL4GraphicsSystem::Setup(cpu::Processor* processor,
processor_context = control_->context()->CreateShared();
{
GLContextLock context_lock(control_->context());
xe::ui::gl::GLContextLock context_lock(control_->context());
auto profiler_display =
std::make_unique<GL4ProfilerDisplay>(control_.get());
std::make_unique<xe::ui::gl::GLProfilerDisplay>(control_.get());
Profiler::set_display(std::move(profiler_display));
}

View File

@@ -13,10 +13,10 @@
#include <memory>
#include "xenia/gpu/gl4/command_processor.h"
#include "xenia/gpu/gl4/wgl_control.h"
#include "xenia/gpu/graphics_system.h"
#include "xenia/gpu/register_file.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/ui/gl/wgl_control.h"
namespace xe {
namespace gpu {
@@ -67,7 +67,7 @@ class GL4GraphicsSystem : public GraphicsSystem {
RegisterFile register_file_;
std::unique_ptr<CommandProcessor> command_processor_;
std::unique_ptr<WGLControl> control_;
std::unique_ptr<xe::ui::gl::WGLControl> control_;
std::atomic<bool> worker_running_;
kernel::object_ref<kernel::XHostThread> worker_thread_;

View File

@@ -1,568 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/gl4/gl4_profiler_display.h"
#include "third_party/microprofile/microprofileui.h"
#include "xenia/base/assert.h"
#include "xenia/base/math.h"
#include "xenia/gpu/gpu_flags.h"
namespace xe {
namespace gpu {
namespace gl4 {
extern "C" GLEWContext* glewGetContext();
#define MICROPROFILE_MAX_VERTICES (16 << 10)
#define MICROPROFILE_NUM_QUERIES (8 << 10)
#define MAX_FONT_CHARS 256
#define Q0(d, member, v) d[0].member = v
#define Q1(d, member, v) \
d[1].member = v; \
d[3].member = v
#define Q2(d, member, v) d[4].member = v
#define Q3(d, member, v) \
d[2].member = v; \
d[5].member = v
const int FONT_TEX_X = 1024;
const int FONT_TEX_Y = 9;
const uint8_t profiler_font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x78, 0x38, 0x78,
0x7c, 0x7c, 0x3c, 0x44, 0x38, 0x04, 0x44, 0x40, 0x44, 0x44, 0x38, 0x78,
0x38, 0x78, 0x38, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x7c, 0x00, 0x00,
0x40, 0x00, 0x04, 0x00, 0x18, 0x00, 0x40, 0x10, 0x08, 0x40, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x10, 0x38, 0x7c, 0x08, 0x7c, 0x1c, 0x7c, 0x38, 0x38,
0x10, 0x28, 0x28, 0x10, 0x00, 0x20, 0x10, 0x08, 0x10, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x38, 0x38, 0x70, 0x00,
0x1c, 0x10, 0x00, 0x1c, 0x10, 0x70, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x44, 0x44, 0x44, 0x40, 0x40, 0x40, 0x44,
0x10, 0x04, 0x48, 0x40, 0x6c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x10,
0x44, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00,
0x24, 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x30,
0x44, 0x04, 0x18, 0x40, 0x20, 0x04, 0x44, 0x44, 0x10, 0x28, 0x28, 0x3c,
0x44, 0x50, 0x10, 0x10, 0x08, 0x54, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x08, 0x00, 0x10, 0x44, 0x44, 0x40, 0x40, 0x04, 0x28, 0x00, 0x30,
0x10, 0x18, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x44, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x10, 0x04, 0x50, 0x40,
0x54, 0x64, 0x44, 0x44, 0x44, 0x44, 0x40, 0x10, 0x44, 0x44, 0x44, 0x28,
0x28, 0x08, 0x00, 0x38, 0x78, 0x3c, 0x3c, 0x38, 0x20, 0x38, 0x78, 0x30,
0x18, 0x44, 0x10, 0x6c, 0x78, 0x38, 0x78, 0x3c, 0x5c, 0x3c, 0x3c, 0x44,
0x44, 0x44, 0x44, 0x44, 0x7c, 0x00, 0x4c, 0x10, 0x04, 0x08, 0x28, 0x78,
0x40, 0x08, 0x44, 0x44, 0x10, 0x00, 0x7c, 0x50, 0x08, 0x50, 0x00, 0x20,
0x04, 0x38, 0x10, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x10, 0x7c, 0x08,
0x08, 0x54, 0x40, 0x20, 0x04, 0x44, 0x00, 0x30, 0x10, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x78, 0x40, 0x44,
0x78, 0x78, 0x40, 0x7c, 0x10, 0x04, 0x60, 0x40, 0x54, 0x54, 0x44, 0x78,
0x44, 0x78, 0x38, 0x10, 0x44, 0x44, 0x54, 0x10, 0x10, 0x10, 0x00, 0x04,
0x44, 0x40, 0x44, 0x44, 0x78, 0x44, 0x44, 0x10, 0x08, 0x48, 0x10, 0x54,
0x44, 0x44, 0x44, 0x44, 0x60, 0x40, 0x10, 0x44, 0x44, 0x44, 0x28, 0x44,
0x08, 0x00, 0x54, 0x10, 0x18, 0x18, 0x48, 0x04, 0x78, 0x10, 0x38, 0x3c,
0x10, 0x00, 0x28, 0x38, 0x10, 0x20, 0x00, 0x20, 0x04, 0x10, 0x7c, 0x00,
0x7c, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x04, 0x10, 0x5c, 0x40, 0x10,
0x04, 0x00, 0x00, 0x60, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7c, 0x44, 0x40, 0x44, 0x40, 0x40, 0x4c, 0x44,
0x10, 0x04, 0x50, 0x40, 0x44, 0x4c, 0x44, 0x40, 0x54, 0x50, 0x04, 0x10,
0x44, 0x44, 0x54, 0x28, 0x10, 0x20, 0x00, 0x3c, 0x44, 0x40, 0x44, 0x7c,
0x20, 0x44, 0x44, 0x10, 0x08, 0x70, 0x10, 0x54, 0x44, 0x44, 0x44, 0x44,
0x40, 0x38, 0x10, 0x44, 0x44, 0x54, 0x10, 0x44, 0x10, 0x00, 0x64, 0x10,
0x20, 0x04, 0x7c, 0x04, 0x44, 0x20, 0x44, 0x04, 0x10, 0x00, 0x7c, 0x14,
0x20, 0x54, 0x00, 0x20, 0x04, 0x38, 0x10, 0x10, 0x00, 0x00, 0x20, 0x10,
0x10, 0x10, 0x7c, 0x08, 0x10, 0x58, 0x40, 0x08, 0x04, 0x00, 0x00, 0x30,
0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x44, 0x44, 0x44, 0x40, 0x40, 0x44, 0x44, 0x10, 0x44, 0x48, 0x40,
0x44, 0x44, 0x44, 0x40, 0x48, 0x48, 0x44, 0x10, 0x44, 0x28, 0x6c, 0x44,
0x10, 0x40, 0x00, 0x44, 0x44, 0x40, 0x44, 0x40, 0x20, 0x3c, 0x44, 0x10,
0x08, 0x48, 0x10, 0x54, 0x44, 0x44, 0x44, 0x44, 0x40, 0x04, 0x12, 0x4c,
0x28, 0x54, 0x28, 0x3c, 0x20, 0x00, 0x44, 0x10, 0x40, 0x44, 0x08, 0x44,
0x44, 0x20, 0x44, 0x08, 0x00, 0x00, 0x28, 0x78, 0x44, 0x48, 0x00, 0x10,
0x08, 0x54, 0x10, 0x10, 0x00, 0x00, 0x40, 0x00, 0x10, 0x08, 0x00, 0x10,
0x00, 0x40, 0x40, 0x04, 0x04, 0x00, 0x00, 0x30, 0x10, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x78, 0x38, 0x78,
0x7c, 0x40, 0x3c, 0x44, 0x38, 0x38, 0x44, 0x7c, 0x44, 0x44, 0x38, 0x40,
0x34, 0x44, 0x38, 0x10, 0x38, 0x10, 0x44, 0x44, 0x10, 0x7c, 0x00, 0x3c,
0x78, 0x3c, 0x3c, 0x3c, 0x20, 0x04, 0x44, 0x38, 0x48, 0x44, 0x38, 0x44,
0x44, 0x38, 0x78, 0x3c, 0x40, 0x78, 0x0c, 0x34, 0x10, 0x6c, 0x44, 0x04,
0x7c, 0x00, 0x38, 0x38, 0x7c, 0x38, 0x08, 0x38, 0x38, 0x20, 0x38, 0x70,
0x10, 0x00, 0x28, 0x10, 0x00, 0x34, 0x00, 0x08, 0x10, 0x10, 0x00, 0x20,
0x00, 0x10, 0x00, 0x00, 0x20, 0x04, 0x00, 0x20, 0x10, 0x3c, 0x70, 0x00,
0x1c, 0x00, 0x7c, 0x1c, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
GL4ProfilerDisplay::GL4ProfilerDisplay(WGLControl* control)
: control_(control),
program_(0),
vao_(0),
font_texture_(0),
font_handle_(0),
vertex_buffer_(MICROPROFILE_MAX_VERTICES * sizeof(Vertex) * 10,
sizeof(Vertex)),
draw_command_count_(0) {
if (!SetupFont() || !SetupState() || !SetupShaders()) {
// Hrm.
assert_always();
}
// Pass through mouse events.
control->on_mouse_down.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseDown(e.button() == xe::ui::MouseEvent::Button::kLeft,
e.button() == xe::ui::MouseEvent::Button::kRight);
e.set_handled(true);
});
control->on_mouse_up.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseUp();
e.set_handled(true);
});
control->on_mouse_move.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseMove(e.x(), e.y());
e.set_handled(true);
});
control->on_mouse_wheel.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseWheel(e.x(), e.y(), -e.dy());
e.set_handled(true);
});
// Watch for toggle/mode keys and such.
control->on_key_down.AddListener([](xe::ui::KeyEvent& e) {
Profiler::OnKeyDown(e.key_code());
// e.set_handled(true);
});
control->on_key_up.AddListener([](xe::ui::KeyEvent& e) {
Profiler::OnKeyUp(e.key_code());
// e.set_handled(true);
});
}
bool GL4ProfilerDisplay::SetupFont() {
// Setup font lookup table.
for (uint32_t i = 0; i < xe::countof(font_description_.char_offsets); ++i) {
font_description_.char_offsets[i] = 206;
}
for (uint32_t i = 'A'; i <= 'Z'; ++i) {
font_description_.char_offsets[i] = (i - 'A') * 8 + 1;
}
for (uint32_t i = 'a'; i <= 'z'; ++i) {
font_description_.char_offsets[i] = (i - 'a') * 8 + 217;
}
for (uint32_t i = '0'; i <= '9'; ++i) {
font_description_.char_offsets[i] = (i - '0') * 8 + 433;
}
for (uint32_t i = '!'; i <= '/'; ++i) {
font_description_.char_offsets[i] = (i - '!') * 8 + 513;
}
for (uint32_t i = ':'; i <= '@'; ++i) {
font_description_.char_offsets[i] = (i - ':') * 8 + 625 + 8;
}
for (uint32_t i = '['; i <= '_'; ++i) {
font_description_.char_offsets[i] = (i - '[') * 8 + 681 + 8;
}
for (uint32_t i = '{'; i <= '~'; ++i) {
font_description_.char_offsets[i] = (i - '{') * 8 + 721 + 8;
}
// Unpack font bitmap into an RGBA texture.
const int UNPACKED_SIZE = FONT_TEX_X * FONT_TEX_Y * 4;
uint32_t unpacked[UNPACKED_SIZE];
int idx = 0;
int end = FONT_TEX_X * FONT_TEX_Y / 8;
for (int i = 0; i < end; i++) {
uint8_t b = profiler_font[i];
for (int j = 0; j < 8; ++j) {
unpacked[idx++] = b & 0x80 ? 0xFFFFFFFFu : 0;
b <<= 1;
}
}
glCreateTextures(GL_TEXTURE_2D, 1, &font_texture_);
glTextureParameteri(font_texture_, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteri(font_texture_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTextureParameteri(font_texture_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(font_texture_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureStorage2D(font_texture_, 1, GL_RGBA8, FONT_TEX_X, FONT_TEX_Y);
glTextureSubImage2D(font_texture_, 0, 0, 0, FONT_TEX_X, FONT_TEX_Y, GL_RGBA,
GL_UNSIGNED_BYTE, unpacked);
font_handle_ = glGetTextureHandleARB(font_texture_);
glMakeTextureHandleResidentARB(font_handle_);
return true;
}
bool GL4ProfilerDisplay::SetupState() {
if (!vertex_buffer_.Initialize()) {
return false;
}
return true;
}
bool GL4ProfilerDisplay::SetupShaders() {
const std::string header =
"\n\
#version 450 \n\
#extension GL_ARB_bindless_texture : require \n\
#extension GL_ARB_explicit_uniform_location : require \n\
#extension GL_ARB_shading_language_420pack : require \n\
precision highp float; \n\
precision highp int; \n\
layout(std140, column_major) uniform; \n\
layout(std430, column_major) buffer; \n\
";
const std::string vertex_shader_source = header +
"\n\
layout(location = 0) uniform mat4 projection_matrix; \n\
layout(location = 0) in vec2 in_pos; \n\
layout(location = 1) in vec4 in_color; \n\
layout(location = 2) in vec2 in_uv; \n\
layout(location = 0) out vec4 vtx_color; \n\
layout(location = 1) out vec2 vtx_uv; \n\
void main() { \n\
gl_Position = projection_matrix * vec4(in_pos.xy, 0.0, 1.0); \n\
vtx_color = in_color; \n\
vtx_uv = in_uv; \n\
} \n\
";
const std::string fragment_shader_source = header +
"\n\
layout(location = 1, bindless_sampler) uniform sampler2D font_texture; \n\
layout(location = 2) uniform float font_height; \n\
layout(location = 0) in vec4 vtx_color; \n\
layout(location = 1) in vec2 vtx_uv; \n\
layout(location = 0) out vec4 oC; \n\
void main() { \n\
if (vtx_uv.x > 1.0) { \n\
oC = vtx_color; \n\
} else { \n\
vec4 color = texture(font_texture, vtx_uv); \n\
oC = color.rgba * vtx_color; \n\
if (color.a < 0.5) { \n\
vec4 c1 = texture(font_texture, vtx_uv + vec2(0.0, font_height)); \n\
oC = vec4(0, 0, 0, c1.a); \n\
} \n\
} \n\
} \n\
";
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
const char* vertex_shader_source_ptr = vertex_shader_source.c_str();
GLint vertex_shader_source_length = GLint(vertex_shader_source.size());
glShaderSource(vertex_shader, 1, &vertex_shader_source_ptr,
&vertex_shader_source_length);
glCompileShader(vertex_shader);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
const char* fragment_shader_source_ptr = fragment_shader_source.c_str();
GLint fragment_shader_source_length = GLint(fragment_shader_source.size());
glShaderSource(fragment_shader, 1, &fragment_shader_source_ptr,
&fragment_shader_source_length);
glCompileShader(fragment_shader);
program_ = glCreateProgram();
glAttachShader(program_, vertex_shader);
glAttachShader(program_, fragment_shader);
glLinkProgram(program_);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
glProgramUniformHandleui64ARB(program_, 1, font_handle_);
glProgramUniform1f(program_, 2, 1.0f / FONT_TEX_Y);
glCreateVertexArrays(1, &vao_);
glEnableVertexArrayAttrib(vao_, 0);
glVertexArrayAttribBinding(vao_, 0, 0);
glVertexArrayAttribFormat(vao_, 0, 2, GL_FLOAT, GL_FALSE,
offsetof(Vertex, x));
glEnableVertexArrayAttrib(vao_, 1);
glVertexArrayAttribBinding(vao_, 1, 0);
glVertexArrayAttribFormat(vao_, 1, 4, GL_UNSIGNED_BYTE, GL_TRUE,
offsetof(Vertex, color));
glEnableVertexArrayAttrib(vao_, 2);
glVertexArrayAttribBinding(vao_, 2, 0);
glVertexArrayAttribFormat(vao_, 2, 2, GL_FLOAT, GL_FALSE,
offsetof(Vertex, u));
glVertexArrayVertexBuffer(vao_, 0, vertex_buffer_.handle(), 0,
sizeof(Vertex));
return true;
}
GL4ProfilerDisplay::~GL4ProfilerDisplay() {
vertex_buffer_.Shutdown();
glMakeTextureHandleNonResidentARB(font_handle_);
glDeleteTextures(1, &font_texture_);
glDeleteVertexArrays(1, &vao_);
glDeleteProgram(program_);
}
uint32_t GL4ProfilerDisplay::width() const { return control_->width(); }
uint32_t GL4ProfilerDisplay::height() const { return control_->height(); }
void GL4ProfilerDisplay::Begin() {
glEnablei(GL_BLEND, 0);
glBlendFunci(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
glViewport(0, 0, control_->width(), control_->height());
float left = 0.0f;
float right = float(width());
float bottom = float(height());
float top = 0.0f;
float z_near = -1.0f;
float z_far = 1.0f;
float projection[16] = {0};
projection[0] = 2.0f / (right - left);
projection[5] = 2.0f / (top - bottom);
projection[10] = -2.0f / (z_far - z_near);
projection[12] = -(right + left) / (right - left);
projection[13] = -(top + bottom) / (top - bottom);
projection[14] = -(z_far + z_near) / (z_far - z_near);
projection[15] = 1.0f;
glProgramUniformMatrix4fv(program_, 0, 1, GL_FALSE, projection);
glUseProgram(program_);
glBindVertexArray(vao_);
}
void GL4ProfilerDisplay::End() {
Flush();
glUseProgram(0);
glBindVertexArray(0);
}
GL4ProfilerDisplay::Vertex* GL4ProfilerDisplay::BeginVertices(size_t count) {
if (draw_command_count_ + 1 > kMaxCommands) {
Flush();
}
size_t total_length = sizeof(Vertex) * count;
if (!vertex_buffer_.CanAcquire(total_length)) {
Flush();
}
current_allocation_ = vertex_buffer_.Acquire(total_length);
return reinterpret_cast<Vertex*>(current_allocation_.host_ptr);
}
void GL4ProfilerDisplay::EndVertices(GLenum prim_type) {
size_t vertex_count = current_allocation_.length / sizeof(Vertex);
if (draw_command_count_ &&
draw_commands_[draw_command_count_ - 1].prim_type == prim_type) {
// Coalesce.
auto& prev_command = draw_commands_[draw_command_count_ - 1];
prev_command.vertex_count += vertex_count;
} else {
auto& command = draw_commands_[draw_command_count_++];
command.prim_type = prim_type;
command.vertex_offset = current_allocation_.offset / sizeof(Vertex);
command.vertex_count = vertex_count;
}
vertex_buffer_.Commit(std::move(current_allocation_));
}
void GL4ProfilerDisplay::Flush() {
if (!draw_command_count_) {
return;
}
vertex_buffer_.Flush();
for (size_t i = 0; i < draw_command_count_; ++i) {
glDrawArrays(draw_commands_[i].prim_type,
GLint(draw_commands_[i].vertex_offset),
GLsizei(draw_commands_[i].vertex_count));
}
draw_command_count_ = 0;
// TODO(benvanik): don't finish here.
vertex_buffer_.WaitUntilClean();
}
void GL4ProfilerDisplay::DrawBox(int x0, int y0, int x1, int y1, uint32_t color,
BoxType type) {
auto v = BeginVertices(6);
if (type == BoxType::kFlat) {
color =
((color & 0xff) << 16) | ((color >> 16) & 0xff) | (0xff00ff00 & color);
Q0(v, x, (float)x0);
Q0(v, y, (float)y0);
Q0(v, color, color);
Q0(v, u, 2.0f);
Q0(v, v, 2.0f);
Q1(v, x, (float)x1);
Q1(v, y, (float)y0);
Q1(v, color, color);
Q1(v, u, 2.0f);
Q1(v, v, 2.0f);
Q2(v, x, (float)x1);
Q2(v, y, (float)y1);
Q2(v, color, color);
Q2(v, u, 2.0f);
Q2(v, v, 2.0f);
Q3(v, x, (float)x0);
Q3(v, y, (float)y1);
Q3(v, color, color);
Q3(v, u, 2.0f);
Q3(v, v, 2.0f);
} else {
uint32_t r = 0xff & (color >> 16);
uint32_t g = 0xff & (color >> 8);
uint32_t b = 0xff & color;
uint32_t nMax = std::max(std::max(std::max(r, g), b), 30u);
uint32_t nMin = std::min(std::min(std::min(r, g), b), 180u);
uint32_t r0 = 0xff & ((r + nMax) / 2);
uint32_t g0 = 0xff & ((g + nMax) / 2);
uint32_t b0 = 0xff & ((b + nMax) / 2);
uint32_t r1 = 0xff & ((r + nMin) / 2);
uint32_t g1 = 0xff & ((g + nMin) / 2);
uint32_t b1 = 0xff & ((b + nMin) / 2);
uint32_t color0 = (r0 << 0) | (g0 << 8) | (b0 << 16) | (0xff000000 & color);
uint32_t color1 = (r1 << 0) | (g1 << 8) | (b1 << 16) | (0xff000000 & color);
Q0(v, x, (float)x0);
Q0(v, y, (float)y0);
Q0(v, color, color0);
Q0(v, u, 2.0f);
Q0(v, v, 2.0f);
Q1(v, x, (float)x1);
Q1(v, y, (float)y0);
Q1(v, color, color0);
Q1(v, u, 3.0f);
Q1(v, v, 2.0f);
Q2(v, x, (float)x1);
Q2(v, y, (float)y1);
Q2(v, color, color1);
Q2(v, u, 3.0f);
Q2(v, v, 3.0f);
Q3(v, x, (float)x0);
Q3(v, y, (float)y1);
Q3(v, color, color1);
Q3(v, u, 2.0f);
Q3(v, v, 3.0f);
}
EndVertices(GL_TRIANGLES);
}
void GL4ProfilerDisplay::DrawLine2D(uint32_t count, float* vertices,
uint32_t color) {
if (!count || !vertices) {
return;
}
auto v = BeginVertices(2 * (count - 1));
color = 0xff000000 | ((color & 0xff) << 16) | (color & 0xff00ff00) |
((color >> 16) & 0xff);
for (uint32_t i = 0; i < count - 1; ++i) {
v[0].x = vertices[i * 2];
v[0].y = vertices[i * 2 + 1];
v[0].color = color;
v[0].u = 2.0f;
v[0].v = 2.0f;
v[1].x = vertices[(i + 1) * 2];
v[1].y = vertices[(i + 1) * 2 + 1];
v[1].color = color;
v[1].u = 2.0f;
v[1].v = 2.0f;
v += 2;
}
EndVertices(GL_LINES);
}
void GL4ProfilerDisplay::DrawText(int x, int y, uint32_t color,
const char* text, size_t text_length) {
if (!text_length) {
return;
}
const float fOffsetU = 5.0f / 1024.0f;
float fX = (float)x;
float fY = (float)y;
float fY2 = fY + (MICROPROFILE_TEXT_HEIGHT + 1);
auto v = BeginVertices(6 * text_length);
const char* pStr = text;
color = 0xff000000 | ((color & 0xff) << 16) | (color & 0xff00) |
((color >> 16) & 0xff);
for (size_t j = 0; j < text_length; ++j) {
int16_t char_offset = font_description_.char_offsets[(int)*pStr++];
float fOffset = char_offset / 1024.0f;
Q0(v, x, fX);
Q0(v, y, fY);
Q0(v, color, color);
Q0(v, u, fOffset);
Q0(v, v, 0.0f);
Q1(v, x, fX + MICROPROFILE_TEXT_WIDTH);
Q1(v, y, fY);
Q1(v, color, color);
Q1(v, u, fOffset + fOffsetU);
Q1(v, v, 0.0f);
Q2(v, x, fX + MICROPROFILE_TEXT_WIDTH);
Q2(v, y, fY2);
Q2(v, color, color);
Q2(v, u, fOffset + fOffsetU);
Q2(v, v, 1.0f);
Q3(v, x, fX);
Q3(v, y, fY2);
Q3(v, color, color);
Q3(v, u, fOffset);
Q3(v, v, 1.0f);
fX += MICROPROFILE_TEXT_WIDTH + 1;
v += 6;
}
EndVertices(GL_TRIANGLES);
}
} // namespace gl4
} // namespace gpu
} // namespace xe

View File

@@ -1,83 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_GL4_PROFILER_DISPLAY_H_
#define XENIA_GPU_GL4_GL4_PROFILER_DISPLAY_H_
#include "xenia/gpu/gl4/circular_buffer.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/gl4/wgl_control.h"
#include "xenia/profiling.h"
namespace xe {
namespace gpu {
namespace gl4 {
class GL4ProfilerDisplay : public ProfilerDisplay {
public:
GL4ProfilerDisplay(WGLControl* control);
virtual ~GL4ProfilerDisplay();
uint32_t width() const override;
uint32_t height() const override;
// TODO(benvanik): GPU timestamping.
void Begin() override;
void End() override;
void DrawBox(int x0, int y0, int x1, int y1, uint32_t color,
BoxType type) override;
void DrawLine2D(uint32_t count, float* vertices, uint32_t color) override;
void DrawText(int x, int y, uint32_t color, const char* text,
size_t text_length) override;
private:
struct Vertex {
float x;
float y;
uint32_t color;
float u;
float v;
};
bool SetupFont();
bool SetupState();
bool SetupShaders();
Vertex* BeginVertices(size_t count);
void EndVertices(GLenum prim_type);
void Flush();
WGLControl* control_;
GLuint program_;
GLuint vao_;
GLuint font_texture_;
GLuint64 font_handle_;
CircularBuffer vertex_buffer_;
static const size_t kMaxCommands = 32;
struct {
GLenum prim_type;
size_t vertex_offset;
size_t vertex_count;
} draw_commands_[kMaxCommands];
uint32_t draw_command_count_;
CircularBuffer::Allocation current_allocation_;
struct {
uint16_t char_offsets[256];
} font_description_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_GL4_PROFILER_DISPLAY_H_

View File

@@ -22,8 +22,6 @@ namespace gl4 {
using namespace xe::gpu::xenos;
extern "C" GLEWContext* glewGetContext();
GL4Shader::GL4Shader(ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count)
: Shader(shader_type, data_hash, dword_ptr, dword_count),

View File

@@ -12,8 +12,8 @@
#include <string>
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/shader.h"
#include "xenia/ui/gl/gl_context.h"
namespace xe {
namespace gpu {

View File

@@ -13,10 +13,10 @@
#include <string>
#include "xenia/base/string_buffer.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/gl4/gl4_shader.h"
#include "xenia/gpu/ucode.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/gl/gl_context.h"
namespace xe {
namespace gpu {

View File

@@ -1,393 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/gl4/gl_context.h"
#include <mutex>
#include <string>
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/gpu/gl4/gl4_gpu_flags.h"
#include "xenia/profiling.h"
namespace xe {
namespace gpu {
namespace gl4 {
static std::recursive_mutex global_gl_mutex_;
thread_local GLEWContext* tls_glew_context_ = nullptr;
thread_local WGLEWContext* tls_wglew_context_ = nullptr;
extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; }
extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; }
GLContext::GLContext() : hwnd_(nullptr), dc_(nullptr), glrc_(nullptr) {}
GLContext::GLContext(HWND hwnd, HGLRC glrc)
: hwnd_(hwnd), dc_(nullptr), glrc_(glrc) {
dc_ = GetDC(hwnd);
}
GLContext::~GLContext() {
MakeCurrent();
blitter_.Shutdown();
ClearCurrent();
if (glrc_) {
wglDeleteContext(glrc_);
}
if (dc_) {
ReleaseDC(hwnd_, dc_);
}
}
bool GLContext::Initialize(HWND hwnd) {
hwnd_ = hwnd;
dc_ = GetDC(hwnd);
PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int pixel_format = ChoosePixelFormat(dc_, &pfd);
if (!pixel_format) {
XELOGE("Unable to choose pixel format");
return false;
}
if (!SetPixelFormat(dc_, pixel_format, &pfd)) {
XELOGE("Unable to set pixel format");
return false;
}
HGLRC temp_context = wglCreateContext(dc_);
if (!temp_context) {
XELOGE("Unable to create temporary GL context");
return false;
}
wglMakeCurrent(dc_, temp_context);
tls_glew_context_ = &glew_context_;
tls_wglew_context_ = &wglew_context_;
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
XELOGE("Unable to initialize GLEW");
return false;
}
if (wglewInit() != GLEW_OK) {
XELOGE("Unable to initialize WGLEW");
return false;
}
if (!WGLEW_ARB_create_context) {
XELOGE("WGL_ARG_create_context not supported by GL ICD");
return false;
}
int context_flags = 0;
if (FLAGS_gl_debug) {
context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
}
int attrib_list[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 4, //
WGL_CONTEXT_MINOR_VERSION_ARB, 5, //
WGL_CONTEXT_FLAGS_ARB, context_flags, //
0};
glrc_ = wglCreateContextAttribsARB(dc_, nullptr, attrib_list);
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(temp_context);
if (!glrc_) {
XELOGE("Unable to create real GL context");
return false;
}
if (!MakeCurrent()) {
XELOGE("Could not make real GL context current");
return false;
}
XELOGI("Successfully created OpenGL context:");
XELOGI(" GL_VENDOR: %s", glGetString(GL_VENDOR));
XELOGI(" GL_VERSION: %s", glGetString(GL_VERSION));
XELOGI(" GL_RENDERER: %s", glGetString(GL_RENDERER));
XELOGI(" GL_SHADING_LANGUAGE_VERSION: %s",
glGetString(GL_SHADING_LANGUAGE_VERSION));
while (glGetError()) {
// Clearing errors.
}
SetupDebugging();
if (!blitter_.Initialize()) {
XELOGE("Unable to initialize blitter");
ClearCurrent();
return false;
}
ClearCurrent();
return true;
}
std::unique_ptr<GLContext> GLContext::CreateShared() {
assert_not_null(glrc_);
HGLRC new_glrc = nullptr;
{
GLContextLock context_lock(this);
int context_flags = 0;
// int profile = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
int profile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
if (FLAGS_gl_debug) {
context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
}
int attrib_list[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 4, //
WGL_CONTEXT_MINOR_VERSION_ARB, 5, //
WGL_CONTEXT_FLAGS_ARB, context_flags, //
WGL_CONTEXT_PROFILE_MASK_ARB, profile, //
0};
new_glrc = wglCreateContextAttribsARB(dc_, glrc_, attrib_list);
if (!new_glrc) {
XELOGE("Could not create shared context");
return nullptr;
}
}
auto new_context = std::make_unique<GLContext>(hwnd_, new_glrc);
if (!new_context->MakeCurrent()) {
XELOGE("Could not make new GL context current");
return nullptr;
}
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
new_context->ClearCurrent();
XELOGE("Unable to initialize GLEW");
return nullptr;
}
if (wglewInit() != GLEW_OK) {
new_context->ClearCurrent();
XELOGE("Unable to initialize WGLEW");
return nullptr;
}
SetupDebugging();
if (!new_context->blitter_.Initialize()) {
XELOGE("Unable to initialize blitter");
return nullptr;
}
new_context->ClearCurrent();
return new_context;
}
void FatalGLError(std::string error) {
XEFATAL(
(error +
"\nEnsure you have the latest drivers for your GPU and that it supports "
"OpenGL 4.5. See http://xenia.jp/faq/ for more information.").c_str());
}
void GLContext::AssertExtensionsPresent() {
if (!MakeCurrent()) {
XEFATAL("Unable to make GL context current");
return;
}
// Check shader version at least 4.5 (matching GL 4.5).
auto glsl_version_raw =
reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
std::string glsl_version(glsl_version_raw);
if (glsl_version.find("4.50") != 0) {
FatalGLError("OpenGL GLSL version 4.50 is required.");
return;
}
if (!GLEW_ARB_bindless_texture) {
FatalGLError("OpenGL extension ARB_bindless_texture is required.");
return;
}
// TODO(benvanik): figure out why this query fails.
// if (!GLEW_ARB_fragment_coord_conventions) {
// FatalGLError(
// "OpenGL extension ARB_fragment_coord_conventions is required.");
// return;
// }
}
void GLContext::DebugMessage(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar* message) {
const char* source_name = nullptr;
switch (source) {
case GL_DEBUG_SOURCE_API_ARB:
source_name = "OpenGL";
break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
source_name = "Windows";
break;
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
source_name = "Shader Compiler";
break;
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
source_name = "Third Party";
break;
case GL_DEBUG_SOURCE_APPLICATION_ARB:
source_name = "Application";
break;
case GL_DEBUG_SOURCE_OTHER_ARB:
source_name = "Other";
break;
default:
source_name = "(unknown source)";
break;
}
const char* type_name = nullptr;
switch (type) {
case GL_DEBUG_TYPE_ERROR:
type_name = "error";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
type_name = "deprecated behavior";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
type_name = "undefined behavior";
break;
case GL_DEBUG_TYPE_PORTABILITY:
type_name = "portability";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
type_name = "performance";
break;
case GL_DEBUG_TYPE_OTHER:
type_name = "message";
break;
case GL_DEBUG_TYPE_MARKER:
type_name = "marker";
break;
case GL_DEBUG_TYPE_PUSH_GROUP:
type_name = "push group";
break;
case GL_DEBUG_TYPE_POP_GROUP:
type_name = "pop group";
break;
default:
type_name = "(unknown type)";
break;
}
const char* severity_name = nullptr;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH_ARB:
severity_name = "high";
break;
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
severity_name = "medium";
break;
case GL_DEBUG_SEVERITY_LOW_ARB:
severity_name = "low";
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
severity_name = "notification";
break;
default:
severity_name = "(unknown severity)";
break;
}
XELOGE("GL4 %s: %s(%s) %d: %s", source_name, type_name, severity_name, id,
message);
}
void GLAPIENTRY
GLContext::DebugMessageThunk(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar* message, GLvoid* user_param) {
reinterpret_cast<GLContext*>(user_param)
->DebugMessage(source, type, id, severity, length, message);
}
void GLContext::SetupDebugging() {
if (!FLAGS_gl_debug || !FLAGS_gl_debug_output) {
return;
}
glEnable(GL_DEBUG_OUTPUT);
// Synchronous output hurts, but is required if we want to line up the logs.
if (FLAGS_gl_debug_output_synchronous) {
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
} else {
glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
// Enable everything by default.
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL,
GL_TRUE);
// Disable annoying messages.
GLuint disable_message_ids[] = {
0x00020004, // Usage warning: Generic vertex attribute array 0 uses a
// pointer with a small value (0x0000000000000000). Is this
// intended to be used as an offset into a buffer object?
};
glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE,
GLsizei(xe::countof(disable_message_ids)),
disable_message_ids, GL_FALSE);
// Callback will be made from driver threads.
glDebugMessageCallback(reinterpret_cast<GLDEBUGPROC>(&DebugMessageThunk),
this);
}
bool GLContext::MakeCurrent() {
SCOPE_profile_cpu_f("gpu");
if (FLAGS_thread_safe_gl) {
global_gl_mutex_.lock();
}
if (!wglMakeCurrent(dc_, glrc_)) {
if (FLAGS_thread_safe_gl) {
global_gl_mutex_.unlock();
}
XELOGE("Unable to make GL context current");
return false;
}
tls_glew_context_ = &glew_context_;
tls_wglew_context_ = &wglew_context_;
return true;
}
void GLContext::ClearCurrent() {
if (!FLAGS_disable_gl_context_reset) {
wglMakeCurrent(nullptr, nullptr);
}
tls_glew_context_ = nullptr;
tls_wglew_context_ = nullptr;
if (FLAGS_thread_safe_gl) {
global_gl_mutex_.unlock();
}
}
} // namespace gl4
} // namespace gpu
} // namespace xe

View File

@@ -1,74 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_GL_CONTEXT_H_
#define XENIA_GPU_GL4_GL_CONTEXT_H_
#include <memory>
#include "xenia/gpu/gl4/blitter.h"
#include "third_party/GL/glew.h"
#include "third_party/GL/wglew.h"
namespace xe {
namespace gpu {
namespace gl4 {
class GLContext {
public:
GLContext();
GLContext(HWND hwnd, HGLRC glrc);
~GLContext();
bool Initialize(HWND hwnd);
void AssertExtensionsPresent();
HDC dc() const { return dc_; }
std::unique_ptr<GLContext> CreateShared();
bool MakeCurrent();
void ClearCurrent();
Blitter* blitter() { return &blitter_; }
private:
void SetupDebugging();
void DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar* message);
static void GLAPIENTRY
DebugMessageThunk(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar* message, GLvoid* user_param);
HWND hwnd_;
HDC dc_;
HGLRC glrc_;
GLEWContext glew_context_;
WGLEWContext wglew_context_;
Blitter blitter_;
};
struct GLContextLock {
GLContextLock(GLContext* context) : context_(context) {
context_->MakeCurrent();
}
~GLContextLock() { context_->ClearCurrent(); }
private:
GLContext* context_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_GL_CONTEXT_H_

View File

@@ -24,9 +24,6 @@ namespace gl4 {
using namespace xe::gpu::xenos;
extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext();
struct TextureConfig {
TextureFormat texture_format;
GLenum internal_format;

View File

@@ -15,17 +15,21 @@
#include <vector>
#include "xenia/base/mutex.h"
#include "xenia/gpu/gl4/blitter.h"
#include "xenia/gpu/gl4/circular_buffer.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/sampler_info.h"
#include "xenia/gpu/texture_info.h"
#include "xenia/memory.h"
#include "xenia/ui/gl/blitter.h"
#include "xenia/ui/gl/circular_buffer.h"
#include "xenia/ui/gl/gl_context.h"
namespace xe {
namespace gpu {
namespace gl4 {
using xe::ui::gl::Blitter;
using xe::ui::gl::CircularBuffer;
using xe::ui::gl::Rect2D;
class TextureCache {
public:
struct TextureEntry;

View File

@@ -1,127 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/gl4/wgl_control.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/gpu/gl4/gl4_gpu_flags.h"
#include "xenia/profiling.h"
namespace xe {
namespace gpu {
namespace gl4 {
extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext();
WGLControl::WGLControl(xe::ui::Loop* loop)
: xe::ui::win32::Win32Control(Flags::kFlagOwnPaint), loop_(loop) {}
WGLControl::~WGLControl() = default;
bool WGLControl::Create() {
HINSTANCE hInstance = GetModuleHandle(nullptr);
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = Win32Control::WndProcThunk;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = nullptr;
wcex.hIconSm = nullptr;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"XeniaWglClass";
if (!RegisterClassEx(&wcex)) {
XELOGE("WGL RegisterClassEx failed");
return false;
}
// Create window.
DWORD window_style = WS_CHILD | WS_VISIBLE | SS_NOTIFY;
DWORD window_ex_style = 0;
hwnd_ =
CreateWindowEx(window_ex_style, L"XeniaWglClass", L"Xenia", window_style,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
parent_hwnd(), nullptr, hInstance, this);
if (!hwnd_) {
XELOGE("WGL CreateWindow failed");
return false;
}
if (!context_.Initialize(hwnd_)) {
XEFATAL(
"Unable to initialize GL context. Xenia requires OpenGL 4.5. Ensure "
"you have the latest drivers for your GPU and that it supports OpenGL "
"4.5. See http://xenia.jp/faq/ for more information.");
return false;
}
context_.AssertExtensionsPresent();
SetFocus(hwnd_);
OnCreate();
return true;
}
void WGLControl::OnLayout(xe::ui::UIEvent& e) { Control::ResizeToFill(); }
LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) {
switch (message) {
case WM_PAINT: {
SCOPE_profile_cpu_i("gpu", "xe::gpu::gl4::WGLControl::WM_PAINT");
{
GLContextLock context_lock(&context_);
wglSwapIntervalEXT(0);
float clear_color[] = {rand() / (float)RAND_MAX, 1.0f, 0, 1.0f};
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
if (current_paint_callback_) {
current_paint_callback_();
current_paint_callback_ = nullptr;
}
xe::ui::UIEvent e(this);
OnPaint(e);
// TODO(benvanik): profiler present.
Profiler::Present();
}
{
SCOPE_profile_cpu_i("gpu", "xe::gpu::gl4::WGLControl::SwapBuffers");
SwapBuffers(context_.dc());
}
} break;
}
return Win32Control::WndProc(hWnd, message, wParam, lParam);
}
void WGLControl::SynchronousRepaint(std::function<void()> paint_callback) {
SCOPE_profile_cpu_f("gpu");
// We may already have a pending paint from a previous request when we
// were minimized. We just overwrite it.
current_paint_callback_ = std::move(paint_callback);
// This will not return until the WM_PAINT has completed.
// Note, if we are minimized this won't do anything.
RedrawWindow(hwnd(), nullptr, nullptr,
RDW_INTERNALPAINT | RDW_UPDATENOW | RDW_ALLCHILDREN);
}
} // namespace gl4
} // namespace gpu
} // namespace xe

View File

@@ -1,51 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GL4_WGL_CONTROL_H_
#define XENIA_GPU_GL4_WGL_CONTROL_H_
#include <functional>
#include "xenia/base/threading.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/ui/loop.h"
#include "xenia/ui/win32/win32_control.h"
namespace xe {
namespace gpu {
namespace gl4 {
class WGLControl : public xe::ui::win32::Win32Control {
public:
WGLControl(xe::ui::Loop* loop);
~WGLControl() override;
GLContext* context() { return &context_; }
void SynchronousRepaint(std::function<void()> paint_callback);
protected:
bool Create() override;
void OnLayout(xe::ui::UIEvent& e) override;
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) override;
private:
xe::ui::Loop* loop_;
GLContext context_;
std::function<void()> current_paint_callback_;
};
} // namespace gl4
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GL4_WGL_CONTROL_H_

View File

@@ -18,12 +18,12 @@
#include "xenia/base/mapped_memory.h"
#include "xenia/base/math.h"
#include "xenia/emulator.h"
#include "xenia/gpu/gl4/gl_context.h"
#include "xenia/gpu/graphics_system.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/tracing.h"
#include "xenia/gpu/xenos.h"
#include "xenia/profiling.h"
#include "xenia/ui/gl/gl_context.h"
#include "xenia/ui/main_window.h"
// HACK: until we have another impl, we just use gl4 directly.
@@ -2317,9 +2317,6 @@ int trace_viewer_main(std::vector<std::wstring>& args) {
// TODO(benvanik): move to another file.
extern "C" GLEWContext* glewGetContext();
extern "C" WGLEWContext* wglewGetContext();
static int shader_handle, vert_handle, frag_handle;
static int texture_location, proj_mtx_location;
static int position_location, uv_location, colour_location;