231 lines
7.0 KiB
C++
231 lines
7.0 KiB
C++
/**
|
|
******************************************************************************
|
|
* 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_GL4_STATE_DATA_BUILDER_H_
|
|
#define XENIA_GPU_GL4_GL4_STATE_DATA_BUILDER_H_
|
|
|
|
#include "xenia/common.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"
|
|
|
|
namespace xe {
|
|
namespace gpu {
|
|
namespace gl4 {
|
|
|
|
union float4 {
|
|
float v[4];
|
|
struct {
|
|
float x, y, z, w;
|
|
};
|
|
};
|
|
|
|
#pragma pack(push, 4)
|
|
struct DrawArraysIndirectCommand {
|
|
GLuint count;
|
|
GLuint instance_count;
|
|
GLuint first_index;
|
|
GLuint base_instance;
|
|
};
|
|
struct DrawElementsIndirectCommand {
|
|
GLuint count;
|
|
GLuint instance_count;
|
|
GLuint first_index;
|
|
GLint base_vertex;
|
|
GLuint base_instance;
|
|
};
|
|
struct BindlessPtrNV {
|
|
GLuint index;
|
|
GLuint reserved_zero;
|
|
GLuint64 address;
|
|
GLuint64 length;
|
|
};
|
|
struct DrawArraysIndirectBindlessCommandNV {
|
|
DrawArraysIndirectCommand cmd;
|
|
// NOTE: the spec is wrong here. For fucks sake.
|
|
// GLuint reserved_zero;
|
|
BindlessPtrNV vertex_buffers[8];
|
|
};
|
|
struct DrawElementsIndirectBindlessCommandNV {
|
|
DrawElementsIndirectCommand cmd;
|
|
GLuint reserved_zero;
|
|
BindlessPtrNV index_buffer;
|
|
BindlessPtrNV vertex_buffers[8];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
class DrawBatcher {
|
|
public:
|
|
enum class FlushMode {
|
|
kMakeCoherent,
|
|
kStateChange,
|
|
kReconfigure,
|
|
};
|
|
|
|
DrawBatcher(RegisterFile* register_file);
|
|
|
|
bool Initialize(CircularBuffer* array_data_buffer);
|
|
void Shutdown();
|
|
|
|
PrimitiveType prim_type() const { return batch_state_.prim_type; }
|
|
|
|
void set_window_offset(uint32_t x, uint32_t y) {
|
|
active_draw_.header->window_offset.x = float(x);
|
|
active_draw_.header->window_offset.y = float(y);
|
|
}
|
|
void set_window_scissor(uint32_t left, uint32_t top, uint32_t right,
|
|
uint32_t bottom) {
|
|
active_draw_.header->window_scissor.x = float(left);
|
|
active_draw_.header->window_scissor.y = float(top);
|
|
active_draw_.header->window_scissor.z = float(right);
|
|
active_draw_.header->window_scissor.w = float(bottom);
|
|
}
|
|
void set_window_scalar(float width_scalar, float height_scalar) {
|
|
active_draw_.header->window_offset.z = width_scalar;
|
|
active_draw_.header->window_offset.w = height_scalar;
|
|
}
|
|
void set_viewport_offset(float offset_x, float offset_y, float offset_z) {
|
|
active_draw_.header->viewport_offset.x = offset_x;
|
|
active_draw_.header->viewport_offset.y = offset_y;
|
|
active_draw_.header->viewport_offset.z = offset_z;
|
|
}
|
|
void set_viewport_scale(float scale_x, float scale_y, float scale_z) {
|
|
active_draw_.header->viewport_scale.x = scale_x;
|
|
active_draw_.header->viewport_scale.y = scale_y;
|
|
active_draw_.header->viewport_scale.z = scale_z;
|
|
}
|
|
void set_vtx_fmt(float xy, float z, float w) {
|
|
active_draw_.header->vtx_fmt.x = xy;
|
|
active_draw_.header->vtx_fmt.y = xy;
|
|
active_draw_.header->vtx_fmt.z = z;
|
|
active_draw_.header->vtx_fmt.w = w;
|
|
}
|
|
void set_alpha_test(bool enabled, uint32_t func, float ref) {
|
|
active_draw_.header->alpha_test.x = enabled ? 1.0f : 0.0f;
|
|
active_draw_.header->alpha_test.y = float(func);
|
|
active_draw_.header->alpha_test.z = ref;
|
|
}
|
|
void set_texture_sampler(int index, GLuint64 handle) {
|
|
active_draw_.header->texture_samplers[index] = handle;
|
|
}
|
|
void set_index_buffer(const CircularBuffer::Allocation& allocation) {
|
|
if (has_bindless_mdi_) {
|
|
auto& ptr = active_draw_.draw_elements_bindless_cmd->index_buffer;
|
|
ptr.reserved_zero = 0;
|
|
ptr.index = 0;
|
|
ptr.address = allocation.gpu_ptr;
|
|
ptr.length = allocation.length;
|
|
} else {
|
|
// Offset is used in glDrawElements.
|
|
auto& cmd = active_draw_.draw_elements_cmd;
|
|
size_t index_size = batch_state_.index_type == GL_UNSIGNED_SHORT ? 2 : 4;
|
|
cmd->first_index = GLuint(allocation.offset / index_size);
|
|
}
|
|
}
|
|
void set_vertex_buffer(int index, GLsizei offset, GLsizei stride,
|
|
const CircularBuffer::Allocation& allocation) {
|
|
if (has_bindless_mdi_) {
|
|
BindlessPtrNV* ptr;
|
|
if (batch_state_.indexed) {
|
|
ptr = &active_draw_.draw_elements_bindless_cmd->vertex_buffers[index];
|
|
} else {
|
|
ptr = &active_draw_.draw_arrays_bindless_cmd->vertex_buffers[index];
|
|
}
|
|
ptr->reserved_zero = 0;
|
|
ptr->index = index;
|
|
ptr->address = allocation.gpu_ptr + offset;
|
|
ptr->length = allocation.length - offset;
|
|
}
|
|
}
|
|
|
|
bool ReconfigurePipeline(GL4Shader* vertex_shader, GL4Shader* pixel_shader,
|
|
GLuint pipeline);
|
|
|
|
bool BeginDrawArrays(PrimitiveType prim_type, uint32_t index_count);
|
|
bool BeginDrawElements(PrimitiveType prim_type, uint32_t index_count,
|
|
xenos::IndexFormat index_format);
|
|
void DiscardDraw();
|
|
bool CommitDraw();
|
|
bool Flush(FlushMode mode);
|
|
|
|
private:
|
|
bool BeginDraw();
|
|
void CopyConstants();
|
|
|
|
RegisterFile* register_file_;
|
|
CircularBuffer command_buffer_;
|
|
CircularBuffer state_buffer_;
|
|
CircularBuffer* array_data_buffer_;
|
|
|
|
bool has_bindless_mdi_;
|
|
|
|
struct BatchState {
|
|
bool needs_reconfigure;
|
|
PrimitiveType prim_type;
|
|
bool indexed;
|
|
GLenum index_type;
|
|
|
|
GL4Shader* vertex_shader;
|
|
GL4Shader* pixel_shader;
|
|
GLuint pipeline;
|
|
|
|
GLsizei command_stride;
|
|
GLsizei state_stride;
|
|
GLsizei float_consts_offset;
|
|
GLsizei bool_consts_offset;
|
|
GLsizei loop_consts_offset;
|
|
|
|
uintptr_t command_range_start;
|
|
uintptr_t command_range_length;
|
|
uintptr_t state_range_start;
|
|
uintptr_t state_range_length;
|
|
GLsizei draw_count;
|
|
} batch_state_;
|
|
|
|
// This must match GL4Shader's header.
|
|
struct CommonHeader {
|
|
float4 window_offset; // tx,ty,sx,sy
|
|
float4 window_scissor; // x0,y0,x1,y1
|
|
float4 viewport_offset; // tx,ty,tz,?
|
|
float4 viewport_scale; // sx,sy,sz,?
|
|
float4 vtx_fmt; //
|
|
float4 alpha_test; // alpha test enable, func, ref, ?
|
|
|
|
// TODO(benvanik): pack tightly
|
|
GLuint64 texture_samplers[32];
|
|
|
|
float4 float_consts[512];
|
|
uint32_t bool_consts[8];
|
|
uint32_t loop_consts[32];
|
|
};
|
|
struct {
|
|
CircularBuffer::Allocation command_allocation;
|
|
CircularBuffer::Allocation state_allocation;
|
|
|
|
union {
|
|
DrawArraysIndirectCommand* draw_arrays_cmd;
|
|
DrawElementsIndirectCommand* draw_elements_cmd;
|
|
DrawArraysIndirectBindlessCommandNV* draw_arrays_bindless_cmd;
|
|
DrawElementsIndirectBindlessCommandNV* draw_elements_bindless_cmd;
|
|
uintptr_t command_address;
|
|
};
|
|
|
|
CommonHeader* header;
|
|
} active_draw_;
|
|
bool draw_open_;
|
|
};
|
|
|
|
} // namespace gl4
|
|
} // namespace gpu
|
|
} // namespace xe
|
|
|
|
#endif // XENIA_GPU_GL4_GL4_STATE_DATA_BUILDER_H_
|