Moving common GL code out of gpu/.
This commit is contained in:
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user