mirror of https://github.com/xemu-project/xemu.git
402 lines
12 KiB
C
402 lines
12 KiB
C
/*
|
|
* QEMU Geforce NV2A PGRAPH internal definitions
|
|
*
|
|
* Copyright (c) 2012 espes
|
|
* Copyright (c) 2015 Jannik Vogel
|
|
* Copyright (c) 2018-2024 Matt Borgerson
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef HW_XBOX_NV2A_PGRAPH_H
|
|
#define HW_XBOX_NV2A_PGRAPH_H
|
|
|
|
#include "xemu-config.h"
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/bitmap.h"
|
|
#include "qemu/units.h"
|
|
#include "qemu/thread.h"
|
|
#include "cpu.h"
|
|
|
|
#include "shaders.h"
|
|
#include "surface.h"
|
|
#include "util.h"
|
|
|
|
typedef struct NV2AState NV2AState;
|
|
typedef struct PGRAPHNullState PGRAPHNullState;
|
|
typedef struct PGRAPHGLState PGRAPHGLState;
|
|
typedef struct PGRAPHVkState PGRAPHVkState;
|
|
|
|
typedef struct VertexAttribute {
|
|
bool dma_select;
|
|
hwaddr offset;
|
|
|
|
/* inline arrays are packed in order?
|
|
* Need to pass the offset to converted attributes */
|
|
unsigned int inline_array_offset;
|
|
|
|
float inline_value[4];
|
|
|
|
unsigned int format;
|
|
unsigned int size; /* size of the data type */
|
|
unsigned int count; /* number of components */
|
|
uint32_t stride;
|
|
|
|
bool needs_conversion;
|
|
|
|
float *inline_buffer;
|
|
bool inline_buffer_populated;
|
|
} VertexAttribute;
|
|
|
|
typedef struct Surface {
|
|
bool draw_dirty;
|
|
bool buffer_dirty;
|
|
bool write_enabled_cache;
|
|
unsigned int pitch;
|
|
|
|
hwaddr offset;
|
|
} Surface;
|
|
|
|
typedef struct KelvinState {
|
|
hwaddr object_instance;
|
|
} KelvinState;
|
|
|
|
typedef struct ContextSurfaces2DState {
|
|
hwaddr object_instance;
|
|
hwaddr dma_image_source;
|
|
hwaddr dma_image_dest;
|
|
unsigned int color_format;
|
|
unsigned int source_pitch, dest_pitch;
|
|
hwaddr source_offset, dest_offset;
|
|
} ContextSurfaces2DState;
|
|
|
|
typedef struct ImageBlitState {
|
|
hwaddr object_instance;
|
|
hwaddr context_surfaces;
|
|
unsigned int operation;
|
|
unsigned int in_x, in_y;
|
|
unsigned int out_x, out_y;
|
|
unsigned int width, height;
|
|
} ImageBlitState;
|
|
|
|
typedef struct BetaState {
|
|
hwaddr object_instance;
|
|
uint32_t beta;
|
|
} BetaState;
|
|
|
|
typedef struct PGRAPHRenderer {
|
|
CONFIG_DISPLAY_RENDERER type;
|
|
const char *name;
|
|
struct {
|
|
void (*early_context_init)(void);
|
|
void (*init)(NV2AState *d, Error **errp);
|
|
void (*finalize)(NV2AState *d);
|
|
void (*clear_report_value)(NV2AState *d);
|
|
void (*clear_surface)(NV2AState *d, uint32_t parameter);
|
|
void (*draw_begin)(NV2AState *d);
|
|
void (*draw_end)(NV2AState *d);
|
|
void (*flip_stall)(NV2AState *d);
|
|
void (*flush_draw)(NV2AState *d);
|
|
void (*get_report)(NV2AState *d, uint32_t parameter);
|
|
void (*image_blit)(NV2AState *d);
|
|
void (*pre_savevm_trigger)(NV2AState *d);
|
|
void (*pre_savevm_wait)(NV2AState *d);
|
|
void (*pre_shutdown_trigger)(NV2AState *d);
|
|
void (*pre_shutdown_wait)(NV2AState *d);
|
|
void (*process_pending)(NV2AState *d);
|
|
void (*process_pending_reports)(NV2AState *d);
|
|
void (*surface_flush)(NV2AState *d);
|
|
void (*surface_update)(NV2AState *d, bool upload, bool color_write, bool zeta_write);
|
|
void (*set_surface_scale_factor)(NV2AState *d, unsigned int scale);
|
|
unsigned int (*get_surface_scale_factor)(NV2AState *d);
|
|
int (*get_framebuffer_surface)(NV2AState *d);
|
|
} ops;
|
|
} PGRAPHRenderer;
|
|
|
|
typedef struct PGRAPHState {
|
|
QemuMutex lock;
|
|
QemuMutex renderer_lock;
|
|
|
|
uint32_t pending_interrupts;
|
|
uint32_t enabled_interrupts;
|
|
|
|
int frame_time;
|
|
int draw_time;
|
|
|
|
/* subchannels state we're not sure the location of... */
|
|
ContextSurfaces2DState context_surfaces_2d;
|
|
ImageBlitState image_blit;
|
|
KelvinState kelvin;
|
|
BetaState beta;
|
|
|
|
hwaddr dma_color, dma_zeta;
|
|
Surface surface_color, surface_zeta;
|
|
unsigned int surface_type;
|
|
SurfaceShape surface_shape;
|
|
SurfaceShape last_surface_shape;
|
|
|
|
struct {
|
|
int clip_x;
|
|
int clip_width;
|
|
int clip_y;
|
|
int clip_height;
|
|
int width;
|
|
int height;
|
|
} surface_binding_dim; // FIXME: Refactor
|
|
|
|
hwaddr dma_a, dma_b;
|
|
bool texture_dirty[NV2A_MAX_TEXTURES];
|
|
|
|
bool texture_matrix_enable[NV2A_MAX_TEXTURES];
|
|
|
|
hwaddr dma_state;
|
|
hwaddr dma_notifies;
|
|
hwaddr dma_semaphore;
|
|
|
|
hwaddr dma_report;
|
|
hwaddr report_offset;
|
|
bool zpass_pixel_count_enable;
|
|
|
|
hwaddr dma_vertex_a, dma_vertex_b;
|
|
|
|
uint32_t primitive_mode;
|
|
|
|
bool enable_vertex_program_write; // FIXME: Not used anywhere???
|
|
|
|
uint32_t vertex_state_shader_v0[4];
|
|
uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
|
|
bool program_data_dirty;
|
|
|
|
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4];
|
|
bool vsh_constants_dirty[NV2A_VERTEXSHADER_CONSTANTS];
|
|
|
|
/* lighting constant arrays */
|
|
uint32_t ltctxa[NV2A_LTCTXA_COUNT][4];
|
|
bool ltctxa_dirty[NV2A_LTCTXA_COUNT];
|
|
uint32_t ltctxb[NV2A_LTCTXB_COUNT][4];
|
|
bool ltctxb_dirty[NV2A_LTCTXB_COUNT];
|
|
uint32_t ltc1[NV2A_LTC1_COUNT][4];
|
|
bool ltc1_dirty[NV2A_LTC1_COUNT];
|
|
|
|
float material_alpha;
|
|
|
|
// should figure out where these are in lighting context
|
|
float light_infinite_half_vector[NV2A_MAX_LIGHTS][3];
|
|
float light_infinite_direction[NV2A_MAX_LIGHTS][3];
|
|
float light_local_position[NV2A_MAX_LIGHTS][3];
|
|
float light_local_attenuation[NV2A_MAX_LIGHTS][3];
|
|
|
|
float specular_params[6];
|
|
float specular_power;
|
|
float specular_params_back[6];
|
|
float specular_power_back;
|
|
|
|
float point_params[8];
|
|
|
|
VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES];
|
|
uint16_t compressed_attrs;
|
|
uint16_t uniform_attrs;
|
|
uint16_t swizzle_attrs;
|
|
|
|
unsigned int inline_array_length;
|
|
uint32_t inline_array[NV2A_MAX_BATCH_LENGTH];
|
|
|
|
unsigned int inline_elements_length;
|
|
uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH];
|
|
|
|
unsigned int inline_buffer_length;
|
|
|
|
unsigned int draw_arrays_length;
|
|
unsigned int draw_arrays_min_start;
|
|
unsigned int draw_arrays_max_count;
|
|
/* FIXME: Unknown size, possibly endless, 1250 will do for now */
|
|
/* Keep in sync with size used in nv2a.c */
|
|
int32_t draw_arrays_start[1250];
|
|
int32_t draw_arrays_count[1250];
|
|
bool draw_arrays_prevent_connect;
|
|
|
|
uint32_t regs_[0x2000];
|
|
DECLARE_BITMAP(regs_dirty, 0x2000 / sizeof(uint32_t));
|
|
|
|
bool clearing; // FIXME: Internal
|
|
bool waiting_for_nop;
|
|
bool waiting_for_flip;
|
|
bool waiting_for_context_switch;
|
|
|
|
bool flush_pending;
|
|
QemuEvent flush_complete;
|
|
|
|
bool sync_pending;
|
|
QemuEvent sync_complete;
|
|
|
|
bool framebuffer_in_use;
|
|
QemuCond framebuffer_released;
|
|
|
|
unsigned int surface_scale_factor;
|
|
uint8_t *scale_buf;
|
|
|
|
const PGRAPHRenderer *renderer;
|
|
union {
|
|
PGRAPHNullState *null_renderer_state;
|
|
PGRAPHGLState *gl_renderer_state;
|
|
PGRAPHVkState *vk_renderer_state;
|
|
};
|
|
} PGRAPHState;
|
|
|
|
void pgraph_init(NV2AState *d);
|
|
void pgraph_init_thread(NV2AState *d);
|
|
void pgraph_destroy(PGRAPHState *pg);
|
|
void pgraph_context_switch(NV2AState *d, unsigned int channel_id);
|
|
void pgraph_process_pending(NV2AState *d);
|
|
void pgraph_process_pending_reports(NV2AState *d);
|
|
void pgraph_pre_savevm_trigger(NV2AState *d);
|
|
void pgraph_pre_savevm_wait(NV2AState *d);
|
|
void pgraph_pre_shutdown_trigger(NV2AState *d);
|
|
void pgraph_pre_shutdown_wait(NV2AState *d);
|
|
|
|
int pgraph_method(NV2AState *d, unsigned int subchannel, unsigned int method,
|
|
uint32_t parameter, uint32_t *parameters,
|
|
size_t num_words_available, size_t max_lookahead_words,
|
|
bool inc);
|
|
void pgraph_check_within_begin_end_block(PGRAPHState *pg);
|
|
|
|
void *pfifo_thread(void *arg);
|
|
void pfifo_kick(NV2AState *d);
|
|
|
|
void pgraph_renderer_register(const PGRAPHRenderer *renderer);
|
|
|
|
// FIXME: Move from here
|
|
|
|
extern NV2AState *g_nv2a;
|
|
|
|
// FIXME: Add new function pgraph_is_texture_sampler_active()
|
|
|
|
static inline uint32_t pgraph_reg_r(PGRAPHState *pg, unsigned int r)
|
|
{
|
|
assert(r % 4 == 0);
|
|
return pg->regs_[r];
|
|
}
|
|
|
|
static inline void pgraph_reg_w(PGRAPHState *pg, unsigned int r, uint32_t v)
|
|
{
|
|
assert(r % 4 == 0);
|
|
if (pg->regs_[r] != v) {
|
|
bitmap_set(pg->regs_dirty, r / sizeof(uint32_t), 1);
|
|
}
|
|
pg->regs_[r] = v;
|
|
}
|
|
|
|
void pgraph_clear_dirty_reg_map(PGRAPHState *pg);
|
|
|
|
static inline bool pgraph_is_reg_dirty(PGRAPHState *pg, unsigned int reg)
|
|
{
|
|
return test_bit(reg / sizeof(uint32_t), pg->regs_dirty);
|
|
}
|
|
|
|
static inline bool pgraph_is_texture_stage_active(PGRAPHState *pg, unsigned int stage)
|
|
{
|
|
assert(stage < NV2A_MAX_TEXTURES);
|
|
uint32_t mode = (pgraph_reg_r(pg, NV_PGRAPH_SHADERPROG) >> (stage * 5)) & 0x1F;
|
|
return mode != 0 && mode != 4;// && mode != 0x11 && mode != 0x0a && mode != 0x09 && mode != 5;
|
|
}
|
|
|
|
static inline bool pgraph_is_texture_enabled(PGRAPHState *pg, int texture_idx)
|
|
{
|
|
uint32_t ctl_0 = pgraph_reg_r(pg, NV_PGRAPH_TEXCTL0_0 + texture_idx*4);
|
|
return // pgraph_is_texture_stage_active(pg, texture_idx) &&
|
|
GET_MASK(ctl_0, NV_PGRAPH_TEXCTL0_0_ENABLE);
|
|
}
|
|
|
|
static inline bool pgraph_is_texture_format_compressed(PGRAPHState *pg, int color_format)
|
|
{
|
|
return color_format == NV097_SET_TEXTURE_FORMAT_COLOR_L_DXT1_A1R5G5B5 ||
|
|
color_format == NV097_SET_TEXTURE_FORMAT_COLOR_L_DXT23_A8R8G8B8 ||
|
|
color_format == NV097_SET_TEXTURE_FORMAT_COLOR_L_DXT45_A8R8G8B8;
|
|
}
|
|
|
|
static inline bool pgraph_color_write_enabled(PGRAPHState *pg)
|
|
{
|
|
return pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & (
|
|
NV_PGRAPH_CONTROL_0_ALPHA_WRITE_ENABLE
|
|
| NV_PGRAPH_CONTROL_0_RED_WRITE_ENABLE
|
|
| NV_PGRAPH_CONTROL_0_GREEN_WRITE_ENABLE
|
|
| NV_PGRAPH_CONTROL_0_BLUE_WRITE_ENABLE);
|
|
}
|
|
|
|
static inline bool pgraph_zeta_write_enabled(PGRAPHState *pg)
|
|
{
|
|
return pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & (
|
|
NV_PGRAPH_CONTROL_0_ZWRITEENABLE
|
|
| NV_PGRAPH_CONTROL_0_STENCIL_WRITE_ENABLE);
|
|
}
|
|
|
|
static inline void pgraph_apply_anti_aliasing_factor(PGRAPHState *pg,
|
|
unsigned int *width,
|
|
unsigned int *height)
|
|
{
|
|
switch (pg->surface_shape.anti_aliasing) {
|
|
case NV097_SET_SURFACE_FORMAT_ANTI_ALIASING_CENTER_1:
|
|
break;
|
|
case NV097_SET_SURFACE_FORMAT_ANTI_ALIASING_CENTER_CORNER_2:
|
|
if (width) { *width *= 2; }
|
|
break;
|
|
case NV097_SET_SURFACE_FORMAT_ANTI_ALIASING_SQUARE_OFFSET_4:
|
|
if (width) { *width *= 2; }
|
|
if (height) { *height *= 2; }
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline void pgraph_apply_scaling_factor(PGRAPHState *pg,
|
|
unsigned int *width,
|
|
unsigned int *height)
|
|
{
|
|
*width *= pg->surface_scale_factor;
|
|
*height *= pg->surface_scale_factor;
|
|
}
|
|
|
|
void pgraph_get_clear_color(PGRAPHState *pg, float rgba[4]);
|
|
void pgraph_get_clear_depth_stencil_value(PGRAPHState *pg, float *depth, int *stencil);
|
|
|
|
/* Vertex */
|
|
void pgraph_allocate_inline_buffer_vertices(PGRAPHState *pg, unsigned int attr);
|
|
void pgraph_finish_inline_buffer_vertex(PGRAPHState *pg);
|
|
void pgraph_reset_inline_buffers(PGRAPHState *pg);
|
|
void pgraph_reset_draw_arrays(PGRAPHState *pg);
|
|
void pgraph_update_inline_value(VertexAttribute *attr, const uint8_t *data);
|
|
void pgraph_get_inline_values(PGRAPHState *pg, uint16_t attrs,
|
|
float values[NV2A_VERTEXSHADER_ATTRIBUTES][4],
|
|
int *count);
|
|
|
|
/* RDI */
|
|
uint32_t pgraph_rdi_read(PGRAPHState *pg, unsigned int select,
|
|
unsigned int address);
|
|
void pgraph_rdi_write(PGRAPHState *pg, unsigned int select,
|
|
unsigned int address, uint32_t val);
|
|
|
|
static inline void pgraph_argb_pack32_to_rgba_float(uint32_t argb, float *rgba)
|
|
{
|
|
rgba[0] = ((argb >> 16) & 0xFF) / 255.0f; /* red */
|
|
rgba[1] = ((argb >> 8) & 0xFF) / 255.0f; /* green */
|
|
rgba[2] = (argb & 0xFF) / 255.0f; /* blue */
|
|
rgba[3] = ((argb >> 24) & 0xFF) / 255.0f; /* alpha */
|
|
}
|
|
|
|
void pgraph_write_zpass_pixel_cnt_report(NV2AState *d, uint32_t parameter, uint32_t result);
|
|
|
|
#endif
|