Files
Xenia-Canary/src/xenia/gpu/gl4/draw_batcher.h
2015-01-31 22:49:47 -08:00

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_