diff options
Diffstat (limited to 'src/gallium/drivers/r300')
36 files changed, 2546 insertions, 1540 deletions
diff --git a/src/gallium/drivers/r300/Makefile b/src/gallium/drivers/r300/Makefile index 6bb82e5ed08..13152635a65 100644 --- a/src/gallium/drivers/r300/Makefile +++ b/src/gallium/drivers/r300/Makefile @@ -14,12 +14,13 @@ C_SOURCES = \ r300_hyperz.c \ r300_query.c \ r300_render.c \ + r300_render_stencilref.c \ + r300_render_translate.c \ r300_resource.c \ r300_screen.c \ r300_screen_buffer.c \ r300_state.c \ r300_state_derived.c \ - r300_state_invariant.c \ r300_vs.c \ r300_vs_draw.c \ r300_texture.c \ diff --git a/src/gallium/drivers/r300/SConscript b/src/gallium/drivers/r300/SConscript index eb3e1d365e9..552ed4e5bef 100644 --- a/src/gallium/drivers/r300/SConscript +++ b/src/gallium/drivers/r300/SConscript @@ -24,12 +24,13 @@ r300 = env.ConvenienceLibrary( 'r300_hyperz.c', 'r300_query.c', 'r300_render.c', + 'r300_render_stencilref.c', + 'r300_render_translate.c', 'r300_resource.c', 'r300_screen.c', 'r300_screen_buffer.c', 'r300_state.c', 'r300_state_derived.c', - 'r300_state_invariant.c', 'r300_vs.c', 'r300_vs_draw.c', 'r300_texture.c', diff --git a/src/gallium/drivers/r300/r300_blit.c b/src/gallium/drivers/r300/r300_blit.c index 49ec51fd132..97d53a14f86 100644 --- a/src/gallium/drivers/r300/r300_blit.c +++ b/src/gallium/drivers/r300/r300_blit.c @@ -25,8 +25,23 @@ #include "util/u_format.h" -static void r300_blitter_save_states(struct r300_context* r300) +enum r300_blitter_op /* bitmask */ { + R300_CLEAR = 1, + R300_CLEAR_SURFACE = 2, + R300_COPY = 4 +}; + +static void r300_blitter_begin(struct r300_context* r300, enum r300_blitter_op op) +{ + if (r300->query_current) { + r300->blitter_saved_query = r300->query_current; + r300_stop_query(r300); + } + + /* Yeah we have to save all those states to ensure the blitter operation + * is really transparent. The states will be restored by the blitter once + * copying is done. */ util_blitter_save_blend(r300->blitter, r300->blend_state.state); util_blitter_save_depth_stencil_alpha(r300->blitter, r300->dsa_state.state); util_blitter_save_stencil_ref(r300->blitter, &(r300->stencil_ref)); @@ -34,11 +49,34 @@ static void r300_blitter_save_states(struct r300_context* r300) util_blitter_save_fragment_shader(r300->blitter, r300->fs.state); util_blitter_save_vertex_shader(r300->blitter, r300->vs_state.state); util_blitter_save_viewport(r300->blitter, &r300->viewport); - util_blitter_save_clip(r300->blitter, &r300->clip); + util_blitter_save_clip(r300->blitter, (struct pipe_clip_state*)r300->clip_state.state); util_blitter_save_vertex_elements(r300->blitter, r300->velems); - /* XXX this crashes the driver util_blitter_save_vertex_buffers(r300->blitter, r300->vertex_buffer_count, - r300->vertex_buffer); */ + r300->vertex_buffer); + + if (op & (R300_CLEAR_SURFACE | R300_COPY)) + util_blitter_save_framebuffer(r300->blitter, r300->fb_state.state); + + if (op & R300_COPY) { + struct r300_textures_state* state = + (struct r300_textures_state*)r300->textures_state.state; + + util_blitter_save_fragment_sampler_states( + r300->blitter, state->sampler_state_count, + (void**)state->sampler_states); + + util_blitter_save_fragment_sampler_views( + r300->blitter, state->sampler_view_count, + (struct pipe_sampler_view**)state->sampler_views); + } +} + +static void r300_blitter_end(struct r300_context *r300) +{ + if (r300->blitter_saved_query) { + r300_resume_query(r300, r300->blitter_saved_query); + r300->blitter_saved_query = NULL; + } } /* Clear currently bound buffers. */ @@ -48,24 +86,37 @@ static void r300_clear(struct pipe_context* pipe, double depth, unsigned stencil) { - /* XXX Implement fastfill. + /* My notes about fastfill: + * + * 1) Only the zbuffer is cleared. + * + * 2) The zbuffer must be micro-tiled and whole microtiles must be + * written. If microtiling is disabled, it locks up. * - * If fastfill is enabled, a few facts should be considered: + * 3) There is Z Mask RAM which contains a compressed zbuffer and + * it interacts with fastfill. We should figure out how to use it + * to get more performance. + * This is what we know about the Z Mask: * - * 1) Zbuffer must be micro-tiled and whole microtiles must be - * written. + * Each dword of the Z Mask contains compression information + * for 16 4x4 pixel blocks, that is 2 bits for each block. + * On chips with 2 Z pipes, every other dword maps to a different + * pipe. * - * 2) ZB_DEPTHCLEARVALUE is used to clear a zbuffer and Z Mask must be - * equal to 0. + * 4) ZB_DEPTHCLEARVALUE is used to clear the zbuffer and the Z Mask must + * be equal to 0. (clear the Z Mask RAM with zeros) * - * 3) For 16-bit integer buffering, compression causes a hung with one or + * 5) For 16-bit zbuffer, compression causes a hung with one or * two samples and should not be used. * - * 4) Fastfill must not be used if reading of compressed Z data is disabled + * 6) FORCE_COMPRESSED_STENCIL_VALUE should be enabled for stencil clears + * to avoid needless decompression. + * + * 7) Fastfill must not be used if reading of compressed Z data is disabled * and writing of compressed Z data is enabled (RD/WR_COMP_ENABLE), * i.e. it cannot be used to compress the zbuffer. - * (what the hell does that mean and how does it fit in clearing - * the buffers?) + * + * 8) ZB_CB_CLEAR does not interact with fastfill in any way. * * - Marek */ @@ -74,13 +125,45 @@ static void r300_clear(struct pipe_context* pipe, struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)r300->fb_state.state; - r300_blitter_save_states(r300); - + r300_blitter_begin(r300, R300_CLEAR); util_blitter_clear(r300->blitter, fb->width, fb->height, fb->nr_cbufs, buffers, rgba, depth, stencil); + r300_blitter_end(r300); +} + +/* Clear a region of a color surface to a constant value. */ +static void r300_clear_render_target(struct pipe_context *pipe, + struct pipe_surface *dst, + const float *rgba, + unsigned dstx, unsigned dsty, + unsigned width, unsigned height) +{ + struct r300_context *r300 = r300_context(pipe); + + r300_blitter_begin(r300, R300_CLEAR_SURFACE); + util_blitter_clear_render_target(r300->blitter, dst, rgba, + dstx, dsty, width, height); + r300_blitter_end(r300); +} + +/* Clear a region of a depth stencil surface. */ +static void r300_clear_depth_stencil(struct pipe_context *pipe, + struct pipe_surface *dst, + unsigned clear_flags, + double depth, + unsigned stencil, + unsigned dstx, unsigned dsty, + unsigned width, unsigned height) +{ + struct r300_context *r300 = r300_context(pipe); + + r300_blitter_begin(r300, R300_CLEAR_SURFACE); + util_blitter_clear_depth_stencil(r300->blitter, dst, clear_flags, depth, stencil, + dstx, dsty, width, height); + r300_blitter_end(r300); } /* Copy a block of pixels from one surface to another using HW. */ @@ -94,27 +177,12 @@ static void r300_hw_copy_region(struct pipe_context* pipe, unsigned width, unsigned height) { struct r300_context* r300 = r300_context(pipe); - struct r300_textures_state* state = - (struct r300_textures_state*)r300->textures_state.state; - /* Yeah we have to save all those states to ensure this blitter operation - * is really transparent. The states will be restored by the blitter once - * copying is done. */ - r300_blitter_save_states(r300); - util_blitter_save_framebuffer(r300->blitter, r300->fb_state.state); - - util_blitter_save_fragment_sampler_states( - r300->blitter, state->sampler_state_count, - (void**)state->sampler_states); - - util_blitter_save_fragment_sampler_views( - r300->blitter, state->sampler_view_count, - (struct pipe_sampler_view**)state->sampler_views); - - /* Do a copy */ + r300_blitter_begin(r300, R300_COPY); util_blitter_copy_region(r300->blitter, dst, subdst, dstx, dsty, dstz, src, subsrc, srcx, srcy, srcz, width, height, TRUE); + r300_blitter_end(r300); } /* Copy a block of pixels from one surface to another. */ @@ -130,14 +198,6 @@ static void r300_resource_copy_region(struct pipe_context *pipe, enum pipe_format old_format = dst->format; enum pipe_format new_format = old_format; - if (dst->format != src->format) { - debug_printf("r300: Implementation error: Format mismatch in %s\n" - " : src: %s dst: %s\n", __FUNCTION__, - util_format_short_name(src->format), - util_format_short_name(dst->format)); - debug_assert(0); - } - if (!pipe->screen->is_format_supported(pipe->screen, old_format, src->target, src->nr_samples, @@ -188,40 +248,6 @@ static void r300_resource_copy_region(struct pipe_context *pipe, } } -/* Clear a region of a color surface to a constant value. */ -static void r300_clear_render_target(struct pipe_context *pipe, - struct pipe_surface *dst, - const float *rgba, - unsigned dstx, unsigned dsty, - unsigned width, unsigned height) -{ - struct r300_context *r300 = r300_context(pipe); - - r300_blitter_save_states(r300); - util_blitter_save_framebuffer(r300->blitter, r300->fb_state.state); - - util_blitter_clear_render_target(r300->blitter, dst, rgba, - dstx, dsty, width, height); -} - -/* Clear a region of a depth stencil surface. */ -static void r300_clear_depth_stencil(struct pipe_context *pipe, - struct pipe_surface *dst, - unsigned clear_flags, - double depth, - unsigned stencil, - unsigned dstx, unsigned dsty, - unsigned width, unsigned height) -{ - struct r300_context *r300 = r300_context(pipe); - - r300_blitter_save_states(r300); - util_blitter_save_framebuffer(r300->blitter, r300->fb_state.state); - - util_blitter_clear_depth_stencil(r300->blitter, dst, clear_flags, depth, stencil, - dstx, dsty, width, height); -} - void r300_init_blit_functions(struct r300_context *r300) { r300->context.clear = r300_clear; diff --git a/src/gallium/drivers/r300/r300_cb.h b/src/gallium/drivers/r300/r300_cb.h new file mode 100644 index 00000000000..61b28330b0b --- /dev/null +++ b/src/gallium/drivers/r300/r300_cb.h @@ -0,0 +1,142 @@ +/* + * Copyright 2008 Corbin Simpson <[email protected]> + * Copyright 2010 Marek Olšák <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * This file contains macros for building command buffers in memory. + * + * Use NEW_CB for buffers with a varying size and it will also allocate + * the buffer. + * Use BEGIN_CB for arrays with a static size. + * + * Example: + * + * uint32_t cb[3]; + * CB_LOCALS; + * + * BEGIN_CB(cb, 3); + * OUT_CB_REG_SEQ(R500_RB3D_CONSTANT_COLOR_AR, 2); + * OUT_CB(blend_color_red_alpha); + * OUT_CB(blend_color_green_blue); + * END_CB; + * + * And later: + * + * CS_LOCALS; + * WRITE_CS_TABLE(cb, 3); + * + * Or using a little slower variant: + * + * CS_LOCALS; + * BEGIN_CS(cb, 3); + * OUT_CS_TABLE(cb, 3); + * END_CS; + */ + +#ifndef R300_CB_H +#define R300_CB_H + +#include "r300_reg.h" + +/* Yes, I know macros are ugly. However, they are much prettier than the code + * that they neatly hide away, and don't have the cost of function setup, so + * we're going to use them. */ + +#ifdef DEBUG +#define CB_DEBUG(x) x +#else +#define CB_DEBUG(x) +#endif + + +/** + * Command buffer setup. + */ + +#define CB_LOCALS \ + CB_DEBUG(int cs_count = 0;) \ + uint32_t *cs_ptr = NULL; \ + CB_DEBUG((void) cs_count;) (void) cs_ptr; + +#define NEW_CB(ptr, size) do { \ + assert(sizeof(*ptr) == sizeof(uint32_t)); \ + cs_ptr = (ptr) = (uint32_t*)malloc((size) * sizeof(uint32_t)); \ + CB_DEBUG(cs_count = size;) \ +} while (0) + +#define BEGIN_CB(ptr, size) do { \ + assert(sizeof(*ptr) == sizeof(uint32_t)); \ + cs_ptr = ptr; \ + CB_DEBUG(cs_count = size;) \ +} while (0) + +#define BEGIN_CS_AS_CB(r300, size) \ + BEGIN_CB(r300->rws->get_cs_pointer(r300->rws, size), size) + +#define END_CB do { \ + CB_DEBUG(if (cs_count != 0) \ + debug_printf("r300: Warning: cs_count off by %d at (%s, %s:%i)\n", \ + cs_count, __FUNCTION__, __FILE__, __LINE__);) \ +} while (0) + + +/** + * Storing pure DWORDs. + */ + +#define OUT_CB(value) do { \ + *cs_ptr = (value); \ + cs_ptr++; \ + CB_DEBUG(cs_count--;) \ +} while (0) + +#define OUT_CB_TABLE(values, count) do { \ + memcpy(cs_ptr, values, count * sizeof(uint32_t)); \ + cs_ptr += count; \ + CB_DEBUG(cs_count -= count;) \ +} while (0) + +#define OUT_CB_32F(value) \ + OUT_CB(fui(value)); + +#define OUT_CB_REG(register, value) do { \ + assert(register); \ + OUT_CB(CP_PACKET0(register, 0)); \ + OUT_CB(value); \ +} while (0) + +/* Note: This expects count to be the number of registers, + * not the actual packet0 count! */ +#define OUT_CB_REG_SEQ(register, count) do { \ + assert(register); \ + OUT_CB(CP_PACKET0(register, (count) - 1)); \ +} while (0) + +#define OUT_CB_ONE_REG(register, count) do { \ + assert(register); \ + OUT_CB(CP_PACKET0(register, (count) - 1) | RADEON_ONE_REG_WR); \ +} while (0) + +#define OUT_CB_PKT3(op, count) \ + OUT_CB(CP_PACKET3(op, count)) + +#endif /* R300_CB_H */ diff --git a/src/gallium/drivers/r300/r300_chipset.c b/src/gallium/drivers/r300/r300_chipset.c index e6dca66d4a0..21f3b9d2610 100644 --- a/src/gallium/drivers/r300/r300_chipset.c +++ b/src/gallium/drivers/r300/r300_chipset.c @@ -36,6 +36,7 @@ void r300_parse_chipset(struct r300_capabilities* caps) caps->num_vert_fpus = 2; caps->num_tex_units = 16; caps->has_tcl = debug_get_bool_option("RADEON_NO_TCL", FALSE) ? FALSE : TRUE; + caps->has_hiz = TRUE; caps->is_r400 = FALSE; caps->is_r500 = FALSE; caps->high_second_pipe = FALSE; @@ -76,6 +77,7 @@ void r300_parse_chipset(struct r300_capabilities* caps) case 0x4E54: case 0x4E56: caps->family = CHIP_FAMILY_RV350; + caps->has_hiz = FALSE; caps->high_second_pipe = TRUE; break; @@ -106,6 +108,7 @@ void r300_parse_chipset(struct r300_capabilities* caps) case 0x5B64: case 0x5B65: caps->family = CHIP_FAMILY_RV370; + caps->has_hiz = FALSE; caps->high_second_pipe = TRUE; break; @@ -201,24 +204,28 @@ void r300_parse_chipset(struct r300_capabilities* caps) case 0x5954: case 0x5955: caps->family = CHIP_FAMILY_RS480; + caps->has_hiz = FALSE; caps->has_tcl = FALSE; break; case 0x5974: case 0x5975: caps->family = CHIP_FAMILY_RS482; + caps->has_hiz = FALSE; caps->has_tcl = FALSE; break; case 0x5A41: case 0x5A42: caps->family = CHIP_FAMILY_RS400; + caps->has_hiz = FALSE; caps->has_tcl = FALSE; break; case 0x5A61: case 0x5A62: caps->family = CHIP_FAMILY_RC410; + caps->has_hiz = FALSE; caps->has_tcl = FALSE; break; diff --git a/src/gallium/drivers/r300/r300_chipset.h b/src/gallium/drivers/r300/r300_chipset.h index ab649c38573..65750f54e71 100644 --- a/src/gallium/drivers/r300/r300_chipset.h +++ b/src/gallium/drivers/r300/r300_chipset.h @@ -42,6 +42,8 @@ struct r300_capabilities { unsigned num_tex_units; /* Whether or not TCL is physically present */ boolean has_tcl; + /* Some chipsets do not have HiZ RAM. */ + boolean has_hiz; /* Whether or not this is RV350 or newer, including all r400 and r500 * chipsets. The differences compared to the oldest r300 chips are: * - Blend LTE/GTE thresholds diff --git a/src/gallium/drivers/r300/r300_context.c b/src/gallium/drivers/r300/r300_context.c index 88ce1867982..df2874d5bf2 100644 --- a/src/gallium/drivers/r300/r300_context.c +++ b/src/gallium/drivers/r300/r300_context.c @@ -23,22 +23,64 @@ #include "draw/draw_context.h" #include "util/u_memory.h" +#include "util/u_sampler.h" #include "util/u_simple_list.h" #include "util/u_upload_mgr.h" +#include "r300_cb.h" #include "r300_context.h" #include "r300_emit.h" #include "r300_screen.h" #include "r300_screen_buffer.h" -#include "r300_state_invariant.h" #include "r300_winsys.h" #include <inttypes.h> +static void r300_release_referenced_objects(struct r300_context *r300) +{ + struct pipe_framebuffer_state *fb = + (struct pipe_framebuffer_state*)r300->fb_state.state; + struct r300_textures_state *textures = + (struct r300_textures_state*)r300->textures_state.state; + struct r300_query *query, *temp; + unsigned i; + + /* Framebuffer state. */ + for (i = 0; i < fb->nr_cbufs; i++) { + pipe_surface_reference(&fb->cbufs[i], NULL); + } + pipe_surface_reference(&fb->zsbuf, NULL); + + /* Textures. */ + for (i = 0; i < textures->sampler_view_count; i++) + pipe_sampler_view_reference( + (struct pipe_sampler_view**)&textures->sampler_views[i], NULL); + + /* The special dummy texture for texkill. */ + if (r300->texkill_sampler) { + pipe_sampler_view_reference( + (struct pipe_sampler_view**)&r300->texkill_sampler, + NULL); + } + + /* The SWTCL VBO. */ + pipe_resource_reference(&r300->vbo, NULL); + + /* Vertex buffers. */ + for (i = 0; i < r300->vertex_buffer_count; i++) { + pipe_resource_reference(&r300->vertex_buffer[i].buffer, NULL); + } + + /* If there are any queries pending or not destroyed, remove them now. */ + foreach_s(query, temp, &r300->query_list) { + remove_from_list(query); + FREE(query); + } +} + static void r300_destroy_context(struct pipe_context* context) { struct r300_context* r300 = r300_context(context); - struct r300_query* query, * temp; struct r300_atom *atom; util_blitter_destroy(r300->blitter); @@ -54,24 +96,24 @@ static void r300_destroy_context(struct pipe_context* context) } } - /* Free the OQ BO. */ - context->screen->resource_destroy(context->screen, r300->oqbo); - - /* If there are any queries pending or not destroyed, remove them now. */ - foreach_s(query, temp, &r300->query_list) { - remove_from_list(query); - FREE(query); - } - u_upload_destroy(r300->upload_vb); u_upload_destroy(r300->upload_ib); + translate_cache_destroy(r300->tran.translate_cache); + + r300_release_referenced_objects(r300); + + FREE(r300->aa_state.state); FREE(r300->blend_color_state.state); FREE(r300->clip_state.state); FREE(r300->fb_state.state); + FREE(r300->gpu_flush.state); + FREE(r300->hyperz_state.state); + FREE(r300->invariant_state.state); FREE(r300->rs_block_state.state); FREE(r300->scissor_state.state); FREE(r300->textures_state.state); + FREE(r300->vap_invariant_state.state); FREE(r300->viewport_state.state); FREE(r300->ztop_state.state); FREE(r300->fs_constants.state); @@ -99,8 +141,10 @@ static void r300_flush_cb(void *data) static void r300_setup_atoms(struct r300_context* r300) { + boolean is_rv350 = r300->screen->caps.is_rv350; boolean is_r500 = r300->screen->caps.is_r500; boolean has_tcl = r300->screen->caps.has_tcl; + boolean drm_2_3_0 = r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0); /* Create the actual atom list. * @@ -108,44 +152,75 @@ static void r300_setup_atoms(struct r300_context* r300) * can affect performance and conformance if not handled with care. * * Some atoms never change size, others change every emit - those have - * the size of 0 here. */ + * the size of 0 here. + * + * NOTE: The framebuffer state is split into these atoms: + * - gpu_flush (unpipelined regs) + * - aa_state (unpipelined regs) + * - fb_state (unpipelined regs) + * - hyperz_state (unpipelined regs followed by pipelined ones) + * - fb_state_pipelined (pipelined regs) + * The motivation behind this is to be able to emit a strict + * subset of the regs, and to have reasonable register ordering. */ make_empty_list(&r300->atom_list); - R300_INIT_ATOM(invariant_state, 71); - R300_INIT_ATOM(query_start, 4); + /* SC, GB (unpipelined), RB3D (unpipelined), ZB (unpipelined). */ + R300_INIT_ATOM(gpu_flush, 9); + R300_INIT_ATOM(aa_state, 4); + R300_INIT_ATOM(fb_state, 0); + /* ZB (unpipelined), SC. */ + R300_INIT_ATOM(hyperz_state, 6); R300_INIT_ATOM(ztop_state, 2); + /* ZB, FG. */ + R300_INIT_ATOM(dsa_state, is_r500 ? 8 : 6); + /* RB3D. */ R300_INIT_ATOM(blend_state, 8); R300_INIT_ATOM(blend_color_state, is_r500 ? 3 : 2); - R300_INIT_ATOM(clip_state, has_tcl ? 5 + (6 * 4) : 2); - R300_INIT_ATOM(dsa_state, is_r500 ? 8 : 6); - R300_INIT_ATOM(fb_state, 0); - R300_INIT_ATOM(rs_state, 0); + /* SC. */ R300_INIT_ATOM(scissor_state, 3); + /* GB, FG, GA, SU, SC, RB3D. */ + R300_INIT_ATOM(invariant_state, 16 + (is_rv350 ? 4 : 0)); + /* VAP. */ R300_INIT_ATOM(viewport_state, 9); - R300_INIT_ATOM(rs_block_state, 0); - R300_INIT_ATOM(vertex_stream_state, 0); R300_INIT_ATOM(pvs_flush, 2); + R300_INIT_ATOM(vap_invariant_state, 9); + R300_INIT_ATOM(vertex_stream_state, 0); R300_INIT_ATOM(vs_state, 0); R300_INIT_ATOM(vs_constants, 0); - R300_INIT_ATOM(texture_cache_inval, 2); - R300_INIT_ATOM(textures_state, 0); + R300_INIT_ATOM(clip_state, has_tcl ? 5 + (6 * 4) : 2); + /* VAP, RS, GA, GB, SU, SC. */ + R300_INIT_ATOM(rs_block_state, 0); + R300_INIT_ATOM(rs_state, 0); + /* SC, US. */ + R300_INIT_ATOM(fb_state_pipelined, 5 + (drm_2_3_0 ? 3 : 0)); + /* US. */ R300_INIT_ATOM(fs, 0); R300_INIT_ATOM(fs_rc_constant_state, 0); R300_INIT_ATOM(fs_constants, 0); + /* TX. */ + R300_INIT_ATOM(texture_cache_inval, 2); + R300_INIT_ATOM(textures_state, 0); + /* ZB (unpipelined), SU. */ + R300_INIT_ATOM(query_start, 4); /* Replace emission functions for r500. */ - if (r300->screen->caps.is_r500) { + if (is_r500) { r300->fs.emit = r500_emit_fs; r300->fs_rc_constant_state.emit = r500_emit_fs_rc_constant_state; r300->fs_constants.emit = r500_emit_fs_constants; } /* Some non-CSO atoms need explicit space to store the state locally. */ + r300->aa_state.state = CALLOC_STRUCT(r300_aa_state); r300->blend_color_state.state = CALLOC_STRUCT(r300_blend_color_state); - r300->clip_state.state = CALLOC_STRUCT(pipe_clip_state); + r300->clip_state.state = CALLOC_STRUCT(r300_clip_state); r300->fb_state.state = CALLOC_STRUCT(pipe_framebuffer_state); + r300->gpu_flush.state = CALLOC_STRUCT(pipe_framebuffer_state); + r300->hyperz_state.state = CALLOC_STRUCT(r300_hyperz_state); + r300->invariant_state.state = CALLOC_STRUCT(r300_invariant_state); r300->rs_block_state.state = CALLOC_STRUCT(r300_rs_block); r300->scissor_state.state = CALLOC_STRUCT(pipe_scissor_state); r300->textures_state.state = CALLOC_STRUCT(r300_textures_state); + r300->vap_invariant_state.state = CALLOC_STRUCT(r300_vap_invariant_state); r300->viewport_state.state = CALLOC_STRUCT(r300_viewport_state); r300->ztop_state.state = CALLOC_STRUCT(r300_ztop_state); r300->fs_constants.state = CALLOC_STRUCT(r300_constant_buffer); @@ -155,11 +230,112 @@ static void r300_setup_atoms(struct r300_context* r300) } /* Some non-CSO atoms don't use the state pointer. */ - r300->invariant_state.allow_null_state = TRUE; + r300->fb_state_pipelined.allow_null_state = TRUE; r300->fs_rc_constant_state.allow_null_state = TRUE; r300->pvs_flush.allow_null_state = TRUE; r300->query_start.allow_null_state = TRUE; r300->texture_cache_inval.allow_null_state = TRUE; + + /* Some states must be marked dirty here to properly set up + * hardware in the first command stream. */ + r300->invariant_state.dirty = TRUE; + r300->pvs_flush.dirty = TRUE; + r300->vap_invariant_state.dirty = TRUE; + r300->texture_cache_inval.dirty = TRUE; + r300->textures_state.dirty = TRUE; +} + +/* Not every state tracker calls every driver function before the first draw + * call and we must initialize the command buffers somehow. */ +static void r300_init_states(struct pipe_context *pipe) +{ + struct r300_context *r300 = r300_context(pipe); + struct pipe_blend_color bc = {{0}}; + struct pipe_clip_state cs = {{{0}}}; + struct pipe_scissor_state ss = {0}; + struct r300_clip_state *clip = + (struct r300_clip_state*)r300->clip_state.state; + struct r300_gpu_flush *gpuflush = + (struct r300_gpu_flush*)r300->gpu_flush.state; + struct r300_vap_invariant_state *vap_invariant = + (struct r300_vap_invariant_state*)r300->vap_invariant_state.state; + struct r300_invariant_state *invariant = + (struct r300_invariant_state*)r300->invariant_state.state; + struct r300_hyperz_state *hyperz = + (struct r300_hyperz_state*)r300->hyperz_state.state; + CB_LOCALS; + + pipe->set_blend_color(pipe, &bc); + pipe->set_scissor_state(pipe, &ss); + + /* Initialize the clip state. */ + if (r300_context(pipe)->screen->caps.has_tcl) { + pipe->set_clip_state(pipe, &cs); + } else { + BEGIN_CB(clip->cb, 2); + OUT_CB_REG(R300_VAP_CLIP_CNTL, R300_CLIP_DISABLE); + END_CB; + } + + /* Initialize the GPU flush. */ + { + BEGIN_CB(gpuflush->cb_flush_clean, 6); + + /* Flush and free renderbuffer caches. */ + OUT_CB_REG(R300_RB3D_DSTCACHE_CTLSTAT, + R300_RB3D_DSTCACHE_CTLSTAT_DC_FREE_FREE_3D_TAGS | + R300_RB3D_DSTCACHE_CTLSTAT_DC_FLUSH_FLUSH_DIRTY_3D); + OUT_CB_REG(R300_ZB_ZCACHE_CTLSTAT, + R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE | + R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE); + + /* Wait until the GPU is idle. + * This fixes random pixels sometimes appearing probably caused + * by incomplete rendering. */ + OUT_CB_REG(RADEON_WAIT_UNTIL, RADEON_WAIT_3D_IDLECLEAN); + END_CB; + } + + /* Initialize the VAP invariant state. */ + { + BEGIN_CB(vap_invariant->cb, 9); + OUT_CB_REG(VAP_PVS_VTX_TIMEOUT_REG, 0xffff); + OUT_CB_REG_SEQ(R300_VAP_GB_VERT_CLIP_ADJ, 4); + OUT_CB_32F(1.0); + OUT_CB_32F(1.0); + OUT_CB_32F(1.0); + OUT_CB_32F(1.0); + OUT_CB_REG(R300_VAP_PSC_SGN_NORM_CNTL, R300_SGN_NORM_NO_ZERO); + END_CB; + } + + /* Initialize the invariant state. */ + { + BEGIN_CB(invariant->cb, r300->invariant_state.size); + OUT_CB_REG(R300_GB_SELECT, 0); + OUT_CB_REG(R300_FG_FOG_BLEND, 0); + OUT_CB_REG(R300_GA_ROUND_MODE, 1); + OUT_CB_REG(R300_GA_OFFSET, 0); + OUT_CB_REG(R300_SU_TEX_WRAP, 0); + OUT_CB_REG(R300_SU_DEPTH_SCALE, 0x4B7FFFFF); + OUT_CB_REG(R300_SU_DEPTH_OFFSET, 0); + OUT_CB_REG(R300_SC_EDGERULE, 0x2DA49525); + + if (r300->screen->caps.is_rv350) { + OUT_CB_REG(R500_RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD, 0x01010101); + OUT_CB_REG(R500_RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD, 0xFEFEFEFE); + } + END_CB; + } + + /* Initialize the hyperz state. */ + { + BEGIN_CB(&hyperz->cb_begin, 6); + OUT_CB_REG(R300_ZB_BW_CNTL, 0); + OUT_CB_REG(R300_ZB_DEPTHCLEARVALUE, 0); + OUT_CB_REG(R300_SC_HYPERZ, 0x1C); + END_CB; + } } struct pipe_context* r300_create_context(struct pipe_screen* screen, @@ -195,9 +371,6 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300_setup_atoms(r300); - /* Open up the OQ BO. */ - r300->oqbo = pipe_buffer_create(screen, - R300_BIND_OQBO, 4096); make_empty_list(&r300->query_list); r300_init_blit_functions(r300); @@ -207,8 +380,6 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, r300_init_state_functions(r300); r300_init_resource_functions(r300); - r300->invariant_state.dirty = TRUE; - rws->set_flush_cb(r300->rws, r300_flush_cb, r300); r300->dirty_hw++; @@ -227,6 +398,34 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, if (r300->upload_vb == NULL) goto no_upload_vb; + r300->tran.translate_cache = translate_cache_create(); + + r300_init_states(&r300->context); + + /* The KIL opcode needs the first texture unit to be enabled + * on r3xx-r4xx. In order to calm down the CS checker, we bind this + * dummy texture there. */ + if (!r300->screen->caps.is_r500) { + struct pipe_resource *tex; + struct pipe_resource rtempl = {{0}}; + struct pipe_sampler_view vtempl = {{0}}; + + rtempl.target = PIPE_TEXTURE_2D; + rtempl.format = PIPE_FORMAT_I8_UNORM; + rtempl.bind = PIPE_BIND_SAMPLER_VIEW; + rtempl.width0 = 1; + rtempl.height0 = 1; + rtempl.depth0 = 1; + tex = screen->resource_create(screen, &rtempl); + + u_sampler_view_default_template(&vtempl, tex, tex->format); + + r300->texkill_sampler = (struct r300_sampler_view*) + r300->context.create_sampler_view(&r300->context, tex, &vtempl); + + pipe_resource_reference(&tex, NULL); + } + return &r300->context; no_upload_ib: @@ -238,10 +437,7 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, boolean r300_check_cs(struct r300_context *r300, unsigned size) { - struct r300_cs_info cs_info; - - r300->rws->get_cs_info(r300->rws, &cs_info); - return size <= cs_info.free; + return size <= r300->rws->get_cs_free_dwords(r300->rws); } void r300_finish(struct r300_context *r300) diff --git a/src/gallium/drivers/r300/r300_context.h b/src/gallium/drivers/r300/r300_context.h index 48ec52d26cf..50dcd0fc67c 100644 --- a/src/gallium/drivers/r300/r300_context.h +++ b/src/gallium/drivers/r300/r300_context.h @@ -31,6 +31,8 @@ #include "util/u_inlines.h" #include "util/u_transfer.h" +#include "translate/translate_cache.h" + #include "r300_defines.h" #include "r300_screen.h" @@ -59,68 +61,83 @@ struct r300_atom { boolean allow_null_state; }; +struct r300_aa_state { + struct r300_surface *dest; + + uint32_t aa_config; + uint32_t aaresolve_ctl; +}; + struct r300_blend_state { - uint32_t blend_control; /* R300_RB3D_CBLEND: 0x4e04 */ - uint32_t alpha_blend_control; /* R300_RB3D_ABLEND: 0x4e08 */ - uint32_t color_channel_mask; /* R300_RB3D_COLOR_CHANNEL_MASK: 0x4e0c */ - uint32_t rop; /* R300_RB3D_ROPCNTL: 0x4e18 */ - uint32_t dither; /* R300_RB3D_DITHER_CTL: 0x4e50 */ + uint32_t cb[8]; + uint32_t cb_no_readwrite[8]; }; struct r300_blend_color_state { - /* RV515 and earlier */ - uint32_t blend_color; /* R300_RB3D_BLEND_COLOR: 0x4e10 */ - /* R520 and newer */ - uint32_t blend_color_red_alpha; /* R500_RB3D_CONSTANT_COLOR_AR: 0x4ef8 */ - uint32_t blend_color_green_blue; /* R500_RB3D_CONSTANT_COLOR_GB: 0x4efc */ + uint32_t cb[3]; +}; + +struct r300_clip_state { + struct pipe_clip_state clip; + + uint32_t cb[29]; }; struct r300_dsa_state { + struct pipe_depth_stencil_alpha_state dsa; + + /* This is actually a command buffer with named dwords. */ + uint32_t cb_begin; uint32_t alpha_function; /* R300_FG_ALPHA_FUNC: 0x4bd4 */ - uint32_t alpha_reference; /* R500_FG_ALPHA_VALUE: 0x4be0 */ + uint32_t cb_reg_seq; uint32_t z_buffer_control; /* R300_ZB_CNTL: 0x4f00 */ uint32_t z_stencil_control; /* R300_ZB_ZSTENCILCNTL: 0x4f04 */ uint32_t stencil_ref_mask; /* R300_ZB_STENCILREFMASK: 0x4f08 */ + uint32_t cb_reg; uint32_t stencil_ref_bf; /* R500_ZB_STENCILREFMASK_BF: 0x4fd4 */ + /* The second command buffer disables zbuffer reads and writes. */ + uint32_t cb_no_readwrite[8]; + /* Whether a two-sided stencil is enabled. */ boolean two_sided; /* Whether a fallback should be used for a two-sided stencil ref value. */ boolean two_sided_stencil_ref; }; +struct r300_hyperz_state { + /* This is actually a command buffer with named dwords. */ + uint32_t cb_begin; + uint32_t zb_bw_cntl; /* R300_ZB_BW_CNTL */ + uint32_t cb_reg1; + uint32_t zb_depthclearvalue; /* R300_ZB_DEPTHCLEARVALUE */ + uint32_t cb_reg2; + uint32_t sc_hyperz; /* R300_SC_HYPERZ */ +}; + +struct r300_gpu_flush { + uint32_t cb_flush_clean[6]; +}; + struct r300_rs_state { /* Original rasterizer state. */ struct pipe_rasterizer_state rs; /* Draw-specific rasterizer state. */ struct pipe_rasterizer_state rs_draw; - uint32_t vap_control_status; /* R300_VAP_CNTL_STATUS: 0x2140 */ - uint32_t antialiasing_config; /* R300_GB_AA_CONFIG: 0x4020 */ - uint32_t point_size; /* R300_GA_POINT_SIZE: 0x421c */ - uint32_t point_minmax; /* R300_GA_POINT_MINMAX: 0x4230 */ - uint32_t line_control; /* R300_GA_LINE_CNTL: 0x4234 */ - float depth_scale; /* R300_SU_POLY_OFFSET_FRONT_SCALE: 0x42a4 */ - /* R300_SU_POLY_OFFSET_BACK_SCALE: 0x42ac */ - float depth_offset; /* R300_SU_POLY_OFFSET_FRONT_OFFSET: 0x42a8 */ - /* R300_SU_POLY_OFFSET_BACK_OFFSET: 0x42b0 */ - uint32_t polygon_offset_enable; /* R300_SU_POLY_OFFSET_ENABLE: 0x42b4 */ - uint32_t cull_mode; /* R300_SU_CULL_MODE: 0x42b8 */ - uint32_t line_stipple_config; /* R300_GA_LINE_STIPPLE_CONFIG: 0x4328 */ - uint32_t line_stipple_value; /* R300_GA_LINE_STIPPLE_VALUE: 0x4260 */ + /* Command buffers. */ + uint32_t cb_main[25]; + uint32_t cb_poly_offset_zb16[5]; + uint32_t cb_poly_offset_zb24[5]; + + /* The index to cb_main where the cull_mode register value resides. */ + unsigned cull_mode_index; + + /* Whether polygon offset is enabled. */ + boolean polygon_offset_enable; + + /* This is emitted in the draw function. */ uint32_t color_control; /* R300_GA_COLOR_CONTROL: 0x4278 */ - uint32_t polygon_mode; /* R300_GA_POLY_MODE: 0x4288 */ - uint32_t clip_rule; /* R300_SC_CLIP_RULE: 0x43D0 */ - - /* Specifies top of Raster pipe specific enable controls, - * i.e. texture coordinates stuffing for points, lines, triangles */ - uint32_t stuffing_enable; /* R300_GB_ENABLE: 0x4008 */ - - /* Point sprites texture coordinates, 0: lower left, 1: upper right */ - float point_texcoord_left; /* R300_GA_POINT_S0: 0x4200 */ - float point_texcoord_bottom; /* R300_GA_POINT_T0: 0x4204 */ - float point_texcoord_right; /* R300_GA_POINT_S1: 0x4208 */ - float point_texcoord_top; /* R300_GA_POINT_T1: 0x420c */ }; struct r300_rs_block { @@ -163,16 +180,14 @@ struct r300_sampler_view { /* Copy of r300_texture::texture_format_state with format-specific bits * added. */ struct r300_texture_format_state format; + + /* The texture cache region for this texture. */ + uint32_t texcache_region; }; struct r300_texture_fb_state { - /* Colorbuffer. */ - uint32_t colorpitch[R300_MAX_TEXTURE_LEVELS]; /* R300_RB3D_COLORPITCH[0-3]*/ - uint32_t us_out_fmt; /* R300_US_OUT_FMT[0-3] */ - - /* Zbuffer. */ - uint32_t depthpitch[R300_MAX_TEXTURE_LEVELS]; /* R300_RB3D_DEPTHPITCH */ - uint32_t zb_format; /* R300_ZB_FORMAT */ + uint32_t pitch[R300_MAX_TEXTURE_LEVELS]; /* COLORPITCH or DEPTHPITCH. */ + uint32_t format; /* US_OUT_FMT or R300_ZB_FORMAT */ }; struct r300_texture_sampler_state { @@ -205,6 +220,14 @@ struct r300_vertex_stream_state { unsigned count; }; +struct r300_invariant_state { + uint32_t cb[20]; +}; + +struct r300_vap_invariant_state { + uint32_t cb[9]; +}; + struct r300_viewport_state { float xscale; /* R300_VAP_VPORT_XSCALE: 0x2098 */ float xoffset; /* R300_VAP_VPORT_XOFFSET: 0x209c */ @@ -224,7 +247,7 @@ struct r300_ztop_state { struct r300_constant_buffer { /* Buffer of constants */ - float constants[256][4]; + uint32_t constants[256][4]; /* Total number of constants */ unsigned count; }; @@ -239,14 +262,23 @@ struct r300_constant_buffer { struct r300_query { /* The kind of query. Currently only OQ is supported. */ unsigned type; - /* The current count of this query. Required to be at least 32 bits. */ - unsigned int count; - /* The offset of this query into the query buffer, in bytes. */ - unsigned offset; + /* The number of pipes where query results are stored. */ + unsigned num_pipes; + /* How many results have been written, in dwords. It's incremented + * after end_query and flush. */ + unsigned num_results; /* if we've flushed the query */ boolean flushed; /* if begin has been emitted */ boolean begin_emitted; + + /* The buffer where query results are stored. */ + struct r300_winsys_buffer *buffer; + /* The size of the buffer. */ + unsigned buffer_size; + /* The domain of the buffer. */ + enum r300_buffer_domain domain; + /* Linked list members. */ struct r300_query* prev; struct r300_query* next; @@ -268,6 +300,19 @@ struct r300_fence { boolean signalled; }; +struct r300_surface { + struct pipe_surface base; + + /* Winsys buffer backing the texture. */ + struct r300_winsys_buffer *buffer; + + enum r300_buffer_domain domain; + + uint32_t offset; + uint32_t pitch; /* COLORPITCH or DEPTHPITCH. */ + uint32_t format; /* US_OUT_FMT or R300_ZB_FORMAT. */ +}; + struct r300_texture { /* Parent class */ struct u_resource b; @@ -326,9 +371,34 @@ struct r300_vertex_element_state { unsigned count; struct pipe_vertex_element velem[PIPE_MAX_ATTRIBS]; + /* If (velem[i].src_format != hw_format[i]), the vertex buffer + * referenced by this vertex element cannot be used for rendering and + * its vertex data must be translated to hw_format[i]. */ + enum pipe_format hw_format[PIPE_MAX_ATTRIBS]; + unsigned hw_format_size[PIPE_MAX_ATTRIBS]; + + /* The size of the vertex, in dwords. */ + unsigned vertex_size_dwords; + + /* This might mean two things: + * - src_format != hw_format, as discussed above. + * - src_offset % 4 != 0. */ + boolean incompatible_layout; + struct r300_vertex_stream_state vertex_stream; }; +struct r300_translate_context { + /* Translate cache for incompatible vertex offset/stride/format fallback. */ + struct translate_cache *translate_cache; + + /* The vertex buffer slot containing the translated buffer. */ + unsigned vb_slot; + + /* Saved and new vertex element state. */ + void *saved_velems, *new_velems; +}; + struct r300_context { /* Parent class */ struct pipe_context context; @@ -343,21 +413,30 @@ struct r300_context { struct blitter_context* blitter; /* Stencil two-sided reference value fallback. */ struct r300_stencilref_context *stencilref_fallback; + /* For translating vertex buffers having incompatible vertex layout. */ + struct r300_translate_context tran; /* Vertex buffer for rendering. */ struct pipe_resource* vbo; + /* The KIL opcode needs the first texture unit to be enabled + * on r3xx-r4xx. In order to calm down the CS checker, we bind this + * dummy texture there. */ + struct r300_sampler_view *texkill_sampler; /* Offset into the VBO. */ size_t vbo_offset; - /* Occlusion query buffer. */ - struct pipe_resource* oqbo; - /* Query list. */ + /* The currently active query. */ struct r300_query *query_current; + /* The saved query for blitter operations. */ + struct r300_query *blitter_saved_query; + /* Query list. */ struct r300_query query_list; /* Various CSO state objects. */ /* Beginning of atom list. */ struct r300_atom atom_list; + /* Anti-aliasing (MSAA) state. */ + struct r300_atom aa_state; /* Blend state. */ struct r300_atom blend_state; /* Blend color state. */ @@ -374,6 +453,10 @@ struct r300_context { struct r300_atom fs_constants; /* Framebuffer state. */ struct r300_atom fb_state; + /* Framebuffer state (pipelined regs). */ + struct r300_atom fb_state_pipelined; + /* HyperZ state (various SC/ZB bits). */ + struct r300_atom hyperz_state; /* Occlusion query. */ struct r300_atom query_start; /* Rasterizer state. */ @@ -396,8 +479,12 @@ struct r300_context { struct r300_atom ztop_state; /* PVS flush. */ struct r300_atom pvs_flush; + /* VAP invariant state. */ + struct r300_atom vap_invariant_state; /* Texture cache invalidate. */ struct r300_atom texture_cache_inval; + /* GPU flush. */ + struct r300_atom gpu_flush; /* Invariant state. This must be emitted to get the engine started. */ struct r300_atom invariant_state; @@ -414,9 +501,6 @@ struct r300_context { struct vertex_info vertex_info; struct pipe_stencil_ref stencil_ref; - - struct pipe_clip_state clip; - struct pipe_viewport_state viewport; /* Stream locations for SWTCL. */ @@ -434,6 +518,8 @@ struct r300_context { int sprite_coord_enable; /* Whether two-sided color selection is enabled (AKA light_twoside). */ boolean two_sided_color; + /* Incompatible vertex buffer layout? (misaligned stride or buffer_offset) */ + boolean incompatible_vb_layout; /* upload managers */ struct u_upload_mgr *upload_vb; @@ -449,6 +535,11 @@ static INLINE struct r300_query* r300_query(struct pipe_query* q) return (struct r300_query*)q; } +static INLINE struct r300_surface* r300_surface(struct pipe_surface* surf) +{ + return (struct r300_surface*)surf; +} + static INLINE struct r300_texture* r300_texture(struct pipe_resource* tex) { return (struct r300_texture*)tex; @@ -467,6 +558,9 @@ static INLINE struct r300_fragment_shader *r300_fs(struct r300_context *r300) struct pipe_context* r300_create_context(struct pipe_screen* screen, void *priv); +boolean r300_check_cs(struct r300_context *r300, unsigned size); +void r300_finish(struct r300_context *r300); + /* Context initialization. */ struct draw_stage* r300_draw_stage(struct r300_context* r300); void r300_init_blit_functions(struct r300_context *r300); @@ -476,10 +570,29 @@ void r300_init_render_functions(struct r300_context *r300); void r300_init_state_functions(struct r300_context* r300); void r300_init_resource_functions(struct r300_context* r300); -boolean r300_check_cs(struct r300_context *r300, unsigned size); -void r300_finish(struct r300_context *r300); +/* r300_query.c */ +void r300_resume_query(struct r300_context *r300, + struct r300_query *query); +void r300_stop_query(struct r300_context *r300); + +/* r300_render_translate.c */ +void r300_begin_vertex_translate(struct r300_context *r300); +void r300_end_vertex_translate(struct r300_context *r300); +void r300_translate_index_buffer(struct r300_context *r300, + struct pipe_resource **index_buffer, + unsigned *index_size, unsigned index_offset, + unsigned *start, unsigned count); + +/* r300_render_stencilref.c */ +void r300_plug_in_stencil_ref_fallback(struct r300_context *r300); + +/* r300_state.c */ +void r300_mark_fs_code_dirty(struct r300_context *r300); + +/* r300_debug.c */ void r500_dump_rs_block(struct r300_rs_block *rs); + static INLINE boolean CTX_DBG_ON(struct r300_context * ctx, unsigned flags) { return SCREEN_DBG_ON(ctx->screen, flags); diff --git a/src/gallium/drivers/r300/r300_cs.h b/src/gallium/drivers/r300/r300_cs.h index 9c8c273902b..1db7da642bd 100644 --- a/src/gallium/drivers/r300/r300_cs.h +++ b/src/gallium/drivers/r300/r300_cs.h @@ -20,171 +20,133 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/** + * This file contains macros for immediate command submission. + */ + #ifndef R300_CS_H #define R300_CS_H -#include "util/u_math.h" - #include "r300_reg.h" +#include "r300_context.h" #include "r300_winsys.h" /* Yes, I know macros are ugly. However, they are much prettier than the code * that they neatly hide away, and don't have the cost of function setup,so * we're going to use them. */ -#define MAX_CS_SIZE 64 * 1024 / 4 - -#define VERY_VERBOSE_CS 1 -#define VERY_VERBOSE_REGISTERS 1 +#ifdef DEBUG +#define CS_DEBUG(x) x +#else +#define CS_DEBUG(x) +#endif -/* XXX stolen from radeon_reg.h */ -#define RADEON_CP_PACKET0 0x0 - -#define CP_PACKET0(register, count) \ - (RADEON_CP_PACKET0 | ((count) << 16) | ((register) >> 2)) +/** + * Command submission setup. + */ #define CS_LOCALS(context) \ struct r300_context* const cs_context_copy = (context); \ struct r300_winsys_screen *cs_winsys = cs_context_copy->rws; \ - int cs_count = 0; (void) cs_count; - -#define CHECK_CS(size) \ - assert(r300_check_cs(cs_context_copy, (size))) + CS_DEBUG(int cs_count = 0; (void) cs_count;) #define BEGIN_CS(size) do { \ - CHECK_CS(size); \ - if (VERY_VERBOSE_CS) { \ - DBG(cs_context_copy, DBG_CS, "r300: BEGIN_CS, count %d, in %s (%s:%d)\n", \ - size, __FUNCTION__, __FILE__, __LINE__); \ - } \ - cs_winsys->begin_cs(cs_winsys, (size), \ - __FILE__, __FUNCTION__, __LINE__); \ - cs_count = size; \ + assert(r300_check_cs(cs_context_copy, (size))); \ + CS_DEBUG(cs_count = size;) \ +} while (0) + +#ifdef DEBUG +#define END_CS do { \ + if (cs_count != 0) \ + debug_printf("r300: Warning: cs_count off by %d at (%s, %s:%i)\n", \ + cs_count, __FUNCTION__, __FILE__, __LINE__); \ + cs_count = 0; \ } while (0) +#else +#define END_CS +#endif + +/** + * Writing pure DWORDs. + */ #define OUT_CS(value) do { \ - if (VERY_VERBOSE_CS || VERY_VERBOSE_REGISTERS) { \ - DBG(cs_context_copy, DBG_CS, "r300: writing %08x\n", value); \ - } \ cs_winsys->write_cs_dword(cs_winsys, (value)); \ - cs_count--; \ + CS_DEBUG(cs_count--;) \ } while (0) #define OUT_CS_32F(value) do { \ - if (VERY_VERBOSE_CS || VERY_VERBOSE_REGISTERS) { \ - DBG(cs_context_copy, DBG_CS, "r300: writing %f\n", value); \ - } \ cs_winsys->write_cs_dword(cs_winsys, fui(value)); \ - cs_count--; \ + CS_DEBUG(cs_count--;) \ } while (0) #define OUT_CS_REG(register, value) do { \ - if (VERY_VERBOSE_REGISTERS) \ - DBG(cs_context_copy, DBG_CS, "r300: writing 0x%08X to register 0x%04X\n", \ - value, register); \ assert(register); \ cs_winsys->write_cs_dword(cs_winsys, CP_PACKET0(register, 0)); \ cs_winsys->write_cs_dword(cs_winsys, value); \ - cs_count -= 2; \ + CS_DEBUG(cs_count -= 2;) \ } while (0) /* Note: This expects count to be the number of registers, * not the actual packet0 count! */ #define OUT_CS_REG_SEQ(register, count) do { \ - if (VERY_VERBOSE_REGISTERS) \ - DBG(cs_context_copy, DBG_CS, "r300: writing register sequence of %d to 0x%04X\n", \ - count, register); \ assert(register); \ cs_winsys->write_cs_dword(cs_winsys, CP_PACKET0((register), ((count) - 1))); \ - cs_count--; \ + CS_DEBUG(cs_count--;) \ } while (0) #define OUT_CS_TABLE(values, count) do { \ - if (VERY_VERBOSE_REGISTERS) \ - DBG(cs_context_copy, DBG_CS, "r300: writing table of %d dwords\n", count); \ cs_winsys->write_cs_table(cs_winsys, values, count); \ - cs_count -= count; \ + CS_DEBUG(cs_count -= count;) \ } while (0) -#define OUT_CS_BUF_RELOC(bo, offset, rd, wd, flags) do { \ - DBG(cs_context_copy, DBG_CS, "r300: writing relocation for buffer %p, offset %d, " \ - "domains (%d, %d, %d)\n", \ - bo, offset, rd, wd, flags); \ - assert(bo); \ - cs_winsys->write_cs_dword(cs_winsys, offset); \ - r300_buffer_write_reloc(cs_winsys, r300_buffer(bo), rd, wd, flags); \ - cs_count -= 3; \ +#define OUT_CS_ONE_REG(register, count) do { \ + assert(register); \ + cs_winsys->write_cs_dword(cs_winsys, CP_PACKET0((register), ((count) - 1)) | RADEON_ONE_REG_WR); \ + CS_DEBUG(cs_count--;) \ } while (0) - -#define OUT_CS_TEX_RELOC(tex, offset, rd, wd, flags) do { \ - DBG(cs_context_copy, DBG_CS, "r300: writing relocation for texture %p, offset %d, " \ - "domains (%d, %d, %d)\n", \ - tex, offset, rd, wd, flags); \ - assert(tex); \ - cs_winsys->write_cs_dword(cs_winsys, offset); \ - r300_texture_write_reloc(cs_winsys, tex, rd, wd, flags); \ - cs_count -= 3; \ +#define OUT_CS_PKT3(op, count) do { \ + cs_winsys->write_cs_dword(cs_winsys, CP_PACKET3(op, count)); \ + CS_DEBUG(cs_count--;) \ } while (0) -#define OUT_CS_BUF_RELOC_NO_OFFSET(bo, rd, wd, flags) do { \ - DBG(cs_context_copy, DBG_CS, "r300: writing relocation for buffer %p, " \ - "domains (%d, %d, %d)\n", \ - bo, rd, wd, flags); \ +/** + * Writing relocations. + */ + +#define OUT_CS_RELOC(bo, offset, rd, wd, flags) do { \ assert(bo); \ - r300_buffer_write_reloc(cs_winsys, r300_buffer(bo), rd, wd, flags); \ - cs_count -= 2; \ + cs_winsys->write_cs_dword(cs_winsys, offset); \ + cs_winsys->write_cs_reloc(cs_winsys, bo, rd, wd, flags); \ + CS_DEBUG(cs_count -= 3;) \ } while (0) -#define END_CS do { \ - if (VERY_VERBOSE_CS) { \ - DBG(cs_context_copy, DBG_CS, "r300: END_CS in %s (%s:%d)\n", __FUNCTION__, \ - __FILE__, __LINE__); \ - } \ - if (cs_count != 0) \ - debug_printf("r300: Warning: cs_count off by %d\n", cs_count); \ - cs_winsys->end_cs(cs_winsys, __FILE__, __FUNCTION__, __LINE__); \ +#define OUT_CS_BUF_RELOC(bo, offset, rd, wd, flags) do { \ + assert(bo); \ + OUT_CS_RELOC(r300_buffer(bo)->buf, offset, rd, wd, flags); \ } while (0) -#define FLUSH_CS do { \ - if (VERY_VERBOSE_CS) { \ - DBG(cs_context_copy, DBG_CS, "r300: FLUSH_CS in %s (%s:%d)\n\n", __FUNCTION__, \ - __FILE__, __LINE__); \ - } \ - if (SCREEN_DBG_ON(r300->screen, DBG_STATS)) { \ - r300->flush_counter++; \ - } \ - cs_winsys->flush_cs(cs_winsys); \ +#define OUT_CS_TEX_RELOC(tex, offset, rd, wd, flags) do { \ + assert(tex); \ + OUT_CS_RELOC(tex->buffer, offset, rd, wd, flags); \ } while (0) -#define RADEON_ONE_REG_WR (1 << 15) - -#define OUT_CS_ONE_REG(register, count) do { \ - if (VERY_VERBOSE_REGISTERS) \ - DBG(cs_context_copy, DBG_CS, "r300: writing data sequence of %d to 0x%04X\n", \ - count, register); \ - assert(register); \ - cs_winsys->write_cs_dword(cs_winsys, CP_PACKET0((register), ((count) - 1)) | RADEON_ONE_REG_WR); \ - cs_count--; \ +#define OUT_CS_BUF_RELOC_NO_OFFSET(bo, rd, wd, flags) do { \ + assert(bo); \ + cs_winsys->write_cs_reloc(cs_winsys, r300_buffer(bo)->buf, rd, wd, flags); \ + CS_DEBUG(cs_count -= 2;) \ } while (0) -#define CP_PACKET3(op, count) \ - (RADEON_CP_PACKET3 | (op) | ((count) << 16)) -#define OUT_CS_PKT3(op, count) do { \ - cs_winsys->write_cs_dword(cs_winsys, CP_PACKET3(op, count)); \ - cs_count--; \ -} while (0) +/** + * Command buffer emission. + */ -#define OUT_CS_INDEX_RELOC(bo, offset, count, rd, wd, flags) do { \ - DBG(cs_context_copy, DBG_CS, "r300: writing relocation for index buffer %p," \ - "offset %d\n", bo, offset); \ - assert(bo); \ - cs_winsys->write_cs_dword(cs_winsys, offset); \ - cs_winsys->write_cs_dword(cs_winsys, count); \ - cs_winsys->write_cs_reloc(cs_winsys, bo, rd, wd, flags); \ - cs_count -= 4; \ +#define WRITE_CS_TABLE(values, count) do { \ + CS_DEBUG(assert(cs_count == 0);) \ + cs_winsys->write_cs_table(cs_winsys, values, count); \ } while (0) #endif /* R300_CS_H */ diff --git a/src/gallium/drivers/r300/r300_debug.c b/src/gallium/drivers/r300/r300_debug.c index 297791f3ffe..a6cd86e3920 100644 --- a/src/gallium/drivers/r300/r300_debug.c +++ b/src/gallium/drivers/r300/r300_debug.c @@ -29,7 +29,6 @@ static const struct debug_named_value debug_options[] = { { "fp", DBG_FP, "Fragment program handling (for debugging)" }, { "vp", DBG_VP, "Vertex program handling (for debugging)" }, - { "cs", DBG_CS, "Command submissions (for debugging)" }, { "draw", DBG_DRAW, "Draw and emit (for debugging)" }, { "tex", DBG_TEX, "Textures (for debugging)" }, { "texalloc", DBG_TEXALLOC, "Texture allocation (for debugging)" }, @@ -39,6 +38,7 @@ static const struct debug_named_value debug_options[] = { { "anisohq", DBG_ANISOHQ, "High quality anisotropic filtering (for benchmarking)" }, { "notiling", DBG_NO_TILING, "Disable tiling (for benchmarking)" }, { "noimmd", DBG_NO_IMMD, "Disable immediate mode (for benchmarking)" }, + { "fakeocc", DBG_FAKE_OCC, "Use fake occlusion queries (for lulz)" }, { "stats", DBG_STATS, "Gather statistics (for lulz)" }, /* must be last */ diff --git a/src/gallium/drivers/r300/r300_defines.h b/src/gallium/drivers/r300/r300_defines.h index 83c9ec7e399..d510d80a7bb 100644 --- a/src/gallium/drivers/r300/r300_defines.h +++ b/src/gallium/drivers/r300/r300_defines.h @@ -30,13 +30,7 @@ #define R300_RESOURCE_FLAG_TRANSFER PIPE_RESOURCE_FLAG_DRV_PRIV -#define R300_INVALID_FORMAT (~0) - -/* XXX: this is just a bandaid on larger problems in - * r300_screen_buffer.h which doesn't seem to be fully ported to - * gallium-resources. - */ -#define R300_BIND_OQBO (1<<21) +#define R300_INVALID_FORMAT 0xffff /* Tiling flags. */ enum r300_buffer_tiling { diff --git a/src/gallium/drivers/r300/r300_emit.c b/src/gallium/drivers/r300/r300_emit.c index c329c0f30ff..014b382edf3 100644 --- a/src/gallium/drivers/r300/r300_emit.c +++ b/src/gallium/drivers/r300/r300_emit.c @@ -43,21 +43,11 @@ void r300_emit_blend_state(struct r300_context* r300, (struct pipe_framebuffer_state*)r300->fb_state.state; CS_LOCALS(r300); - BEGIN_CS(size); - OUT_CS_REG(R300_RB3D_ROPCNTL, blend->rop); - OUT_CS_REG_SEQ(R300_RB3D_CBLEND, 3); if (fb->nr_cbufs) { - OUT_CS(blend->blend_control); - OUT_CS(blend->alpha_blend_control); - OUT_CS(blend->color_channel_mask); + WRITE_CS_TABLE(blend->cb, size); } else { - OUT_CS(0); - OUT_CS(0); - OUT_CS(0); - /* XXX also disable fastfill here once it's supported */ + WRITE_CS_TABLE(blend->cb_no_readwrite, size); } - OUT_CS_REG(R300_RB3D_DITHER_CTL, blend->dither); - END_CS; } void r300_emit_blend_color_state(struct r300_context* r300, @@ -66,40 +56,16 @@ void r300_emit_blend_color_state(struct r300_context* r300, struct r300_blend_color_state* bc = (struct r300_blend_color_state*)state; CS_LOCALS(r300); - if (r300->screen->caps.is_r500) { - BEGIN_CS(size); - OUT_CS_REG_SEQ(R500_RB3D_CONSTANT_COLOR_AR, 2); - OUT_CS(bc->blend_color_red_alpha); - OUT_CS(bc->blend_color_green_blue); - END_CS; - } else { - BEGIN_CS(size); - OUT_CS_REG(R300_RB3D_BLEND_COLOR, bc->blend_color); - END_CS; - } + WRITE_CS_TABLE(bc->cb, size); } void r300_emit_clip_state(struct r300_context* r300, unsigned size, void* state) { - struct pipe_clip_state* clip = (struct pipe_clip_state*)state; + struct r300_clip_state* clip = (struct r300_clip_state*)state; CS_LOCALS(r300); - if (r300->screen->caps.has_tcl) { - BEGIN_CS(size); - OUT_CS_REG(R300_VAP_PVS_VECTOR_INDX_REG, - (r300->screen->caps.is_r500 ? - R500_PVS_UCP_START : R300_PVS_UCP_START)); - OUT_CS_ONE_REG(R300_VAP_PVS_UPLOAD_DATA, 6 * 4); - OUT_CS_TABLE(clip->ucp, 6 * 4); - OUT_CS_REG(R300_VAP_CLIP_CNTL, ((1 << clip->nr) - 1) | - R300_PS_UCP_MODE_CLIP_AS_TRIFAN); - END_CS; - } else { - BEGIN_CS(size); - OUT_CS_REG(R300_VAP_CLIP_CNTL, R300_CLIP_DISABLE); - END_CS; - } + WRITE_CS_TABLE(clip->cb, size); } void r300_emit_dsa_state(struct r300_context* r300, unsigned size, void* state) @@ -107,27 +73,13 @@ void r300_emit_dsa_state(struct r300_context* r300, unsigned size, void* state) struct r300_dsa_state* dsa = (struct r300_dsa_state*)state; struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)r300->fb_state.state; - struct pipe_stencil_ref stencil_ref = r300->stencil_ref; CS_LOCALS(r300); - BEGIN_CS(size); - OUT_CS_REG(R300_FG_ALPHA_FUNC, dsa->alpha_function); - OUT_CS_REG_SEQ(R300_ZB_CNTL, 3); - if (fb->zsbuf) { - OUT_CS(dsa->z_buffer_control); - OUT_CS(dsa->z_stencil_control); + WRITE_CS_TABLE(&dsa->cb_begin, size); } else { - OUT_CS(0); - OUT_CS(0); + WRITE_CS_TABLE(dsa->cb_no_readwrite, size); } - - OUT_CS(dsa->stencil_ref_mask | stencil_ref.ref_value[0]); - - if (r300->screen->caps.is_r500) { - OUT_CS_REG(R500_ZB_STENCILREFMASK_BF, dsa->stencil_ref_bf | stencil_ref.ref_value[1]); - } - END_CS; } static const float * get_rc_constant_state( @@ -175,7 +127,7 @@ static const float * get_rc_constant_state( /* Convert a normal single-precision float into the 7.16 format * used by the R300 fragment shader. */ -static uint32_t pack_float24(float f) +uint32_t pack_float24(float f) { union { float fl; @@ -206,101 +158,27 @@ static uint32_t pack_float24(float f) return float24; } -unsigned r300_get_fs_atom_size(struct r300_context *r300) -{ - struct r300_fragment_shader *fs = r300_fs(r300); - unsigned imm_count = fs->shader->immediates_count; - struct r300_fragment_program_code *code = &fs->shader->code.code.r300; - - return 19 + - code->alu.length * 4 + - (code->tex.length ? (1 + code->tex.length) : 0) + - (imm_count ? imm_count * 5 : 0); -} - void r300_emit_fs(struct r300_context* r300, unsigned size, void *state) { struct r300_fragment_shader *fs = r300_fs(r300); - struct rX00_fragment_program_code* generic_code = &fs->shader->code; - struct r300_fragment_program_code * code = &generic_code->code.r300; - unsigned i; - unsigned imm_count = fs->shader->immediates_count; - unsigned imm_first = fs->shader->externals_count; - unsigned imm_end = generic_code->constants.Count; - struct rc_constant *constants = generic_code->constants.Constants; CS_LOCALS(r300); - BEGIN_CS(size); - OUT_CS_REG(R300_US_CONFIG, code->config); - OUT_CS_REG(R300_US_PIXSIZE, code->pixsize); - OUT_CS_REG(R300_US_CODE_OFFSET, code->code_offset); - - OUT_CS_REG_SEQ(R300_US_CODE_ADDR_0, 4); - OUT_CS_TABLE(code->code_addr, 4); - - OUT_CS_REG_SEQ(R300_US_ALU_RGB_INST_0, code->alu.length); - for (i = 0; i < code->alu.length; i++) - OUT_CS(code->alu.inst[i].rgb_inst); - - OUT_CS_REG_SEQ(R300_US_ALU_RGB_ADDR_0, code->alu.length); - for (i = 0; i < code->alu.length; i++) - OUT_CS(code->alu.inst[i].rgb_addr); - - OUT_CS_REG_SEQ(R300_US_ALU_ALPHA_INST_0, code->alu.length); - for (i = 0; i < code->alu.length; i++) - OUT_CS(code->alu.inst[i].alpha_inst); - - OUT_CS_REG_SEQ(R300_US_ALU_ALPHA_ADDR_0, code->alu.length); - for (i = 0; i < code->alu.length; i++) - OUT_CS(code->alu.inst[i].alpha_addr); - - if (code->tex.length) { - OUT_CS_REG_SEQ(R300_US_TEX_INST_0, code->tex.length); - OUT_CS_TABLE(code->tex.inst, code->tex.length); - } - - /* Emit immediates. */ - if (imm_count) { - for(i = imm_first; i < imm_end; ++i) { - if (constants[i].Type == RC_CONSTANT_IMMEDIATE) { - const float *data = constants[i].u.Immediate; - - OUT_CS_REG_SEQ(R300_PFS_PARAM_0_X + i * 16, 4); - OUT_CS(pack_float24(data[0])); - OUT_CS(pack_float24(data[1])); - OUT_CS(pack_float24(data[2])); - OUT_CS(pack_float24(data[3])); - } - } - } - - OUT_CS_REG(R300_FG_DEPTH_SRC, fs->shader->fg_depth_src); - OUT_CS_REG(R300_US_W_FMT, fs->shader->us_out_w); - END_CS; + WRITE_CS_TABLE(fs->shader->cb_code, fs->shader->cb_code_size); } void r300_emit_fs_constants(struct r300_context* r300, unsigned size, void *state) { struct r300_fragment_shader *fs = r300_fs(r300); - struct rc_constant_list *constants = &fs->shader->code.constants; struct r300_constant_buffer *buf = (struct r300_constant_buffer*)state; - unsigned i, count = fs->shader->externals_count; + unsigned count = fs->shader->externals_count * 4; CS_LOCALS(r300); if (count == 0) return; BEGIN_CS(size); - OUT_CS_REG_SEQ(R300_PFS_PARAM_0_X, count * 4); - for(i = 0; i < count; ++i) { - const float *data; - assert(constants->Constants[i].Type == RC_CONSTANT_EXTERNAL); - data = buf->constants[i]; - OUT_CS(pack_float24(data[0])); - OUT_CS(pack_float24(data[1])); - OUT_CS(pack_float24(data[2])); - OUT_CS(pack_float24(data[3])); - } + OUT_CS_REG_SEQ(R300_PFS_PARAM_0_X, count); + OUT_CS_TABLE(buf->constants, count); END_CS; } @@ -312,6 +190,8 @@ void r300_emit_fs_rc_constant_state(struct r300_context* r300, unsigned size, vo unsigned count = fs->shader->rc_state_count; unsigned first = fs->shader->externals_count; unsigned end = constants->Count; + uint32_t cdata[4]; + unsigned j; CS_LOCALS(r300); if (count == 0) @@ -323,85 +203,29 @@ void r300_emit_fs_rc_constant_state(struct r300_context* r300, unsigned size, vo const float *data = get_rc_constant_state(r300, &constants->Constants[i]); + for (j = 0; j < 4; j++) + cdata[j] = pack_float24(data[j]); + OUT_CS_REG_SEQ(R300_PFS_PARAM_0_X + i * 16, 4); - OUT_CS(pack_float24(data[0])); - OUT_CS(pack_float24(data[1])); - OUT_CS(pack_float24(data[2])); - OUT_CS(pack_float24(data[3])); + OUT_CS_TABLE(cdata, 4); } } END_CS; } -unsigned r500_get_fs_atom_size(struct r300_context *r300) -{ - struct r300_fragment_shader *fs = r300_fs(r300); - unsigned imm_count = fs->shader->immediates_count; - struct r500_fragment_program_code *code = &fs->shader->code.code.r500; - - return 17 + - ((code->inst_end + 1) * 6) + - (imm_count ? imm_count * 7 : 0); -} - void r500_emit_fs(struct r300_context* r300, unsigned size, void *state) { struct r300_fragment_shader *fs = r300_fs(r300); - struct rX00_fragment_program_code* generic_code = &fs->shader->code; - struct r500_fragment_program_code * code = &generic_code->code.r500; - unsigned i; - unsigned imm_count = fs->shader->immediates_count; - unsigned imm_first = fs->shader->externals_count; - unsigned imm_end = generic_code->constants.Count; - struct rc_constant *constants = generic_code->constants.Constants; CS_LOCALS(r300); - BEGIN_CS(size); - OUT_CS_REG(R500_US_CONFIG, R500_ZERO_TIMES_ANYTHING_EQUALS_ZERO); - OUT_CS_REG(R500_US_PIXSIZE, code->max_temp_idx); - OUT_CS_REG(R500_US_CODE_RANGE, - R500_US_CODE_RANGE_ADDR(0) | R500_US_CODE_RANGE_SIZE(code->inst_end)); - OUT_CS_REG(R500_US_CODE_OFFSET, 0); - OUT_CS_REG(R500_US_CODE_ADDR, - R500_US_CODE_START_ADDR(0) | R500_US_CODE_END_ADDR(code->inst_end)); - - OUT_CS_REG(R500_GA_US_VECTOR_INDEX, R500_GA_US_VECTOR_INDEX_TYPE_INSTR); - OUT_CS_ONE_REG(R500_GA_US_VECTOR_DATA, (code->inst_end + 1) * 6); - for (i = 0; i <= code->inst_end; i++) { - OUT_CS(code->inst[i].inst0); - OUT_CS(code->inst[i].inst1); - OUT_CS(code->inst[i].inst2); - OUT_CS(code->inst[i].inst3); - OUT_CS(code->inst[i].inst4); - OUT_CS(code->inst[i].inst5); - } - - /* Emit immediates. */ - if (imm_count) { - for(i = imm_first; i < imm_end; ++i) { - if (constants[i].Type == RC_CONSTANT_IMMEDIATE) { - const float *data = constants[i].u.Immediate; - - OUT_CS_REG(R500_GA_US_VECTOR_INDEX, - R500_GA_US_VECTOR_INDEX_TYPE_CONST | - (i & R500_GA_US_VECTOR_INDEX_MASK)); - OUT_CS_ONE_REG(R500_GA_US_VECTOR_DATA, 4); - OUT_CS_TABLE(data, 4); - } - } - } - - OUT_CS_REG(R300_FG_DEPTH_SRC, fs->shader->fg_depth_src); - OUT_CS_REG(R300_US_W_FMT, fs->shader->us_out_w); - END_CS; + WRITE_CS_TABLE(fs->shader->cb_code, fs->shader->cb_code_size); } void r500_emit_fs_constants(struct r300_context* r300, unsigned size, void *state) { struct r300_fragment_shader *fs = r300_fs(r300); - struct rc_constant_list *constants = &fs->shader->code.constants; struct r300_constant_buffer *buf = (struct r300_constant_buffer*)state; - unsigned i, count = fs->shader->externals_count; + unsigned count = fs->shader->externals_count * 4; CS_LOCALS(r300); if (count == 0) @@ -409,11 +233,8 @@ void r500_emit_fs_constants(struct r300_context* r300, unsigned size, void *stat BEGIN_CS(size); OUT_CS_REG(R500_GA_US_VECTOR_INDEX, R500_GA_US_VECTOR_INDEX_TYPE_CONST); - OUT_CS_ONE_REG(R500_GA_US_VECTOR_DATA, count * 4); - for(i = 0; i < count; ++i) { - assert(constants->Constants[i].Type == RC_CONSTANT_EXTERNAL); - } - OUT_CS_TABLE(buf->constants, count * 4); + OUT_CS_ONE_REG(R500_GA_US_VECTOR_DATA, count); + OUT_CS_TABLE(buf->constants, count); END_CS; } @@ -446,83 +267,170 @@ void r500_emit_fs_rc_constant_state(struct r300_context* r300, unsigned size, vo END_CS; } +void r300_emit_gpu_flush(struct r300_context *r300, unsigned size, void *state) +{ + struct r300_gpu_flush *gpuflush = (struct r300_gpu_flush*)state; + struct pipe_framebuffer_state* fb = + (struct pipe_framebuffer_state*)r300->fb_state.state; + CS_LOCALS(r300); + + BEGIN_CS(size); + + /* Set up scissors. + * By writing to the SC registers, SC & US assert idle. */ + OUT_CS_REG_SEQ(R300_SC_SCISSORS_TL, 2); + if (r300->screen->caps.is_r500) { + OUT_CS(0); + OUT_CS(((fb->width - 1) << R300_SCISSORS_X_SHIFT) | + ((fb->height - 1) << R300_SCISSORS_Y_SHIFT)); + } else { + OUT_CS((1440 << R300_SCISSORS_X_SHIFT) | + (1440 << R300_SCISSORS_Y_SHIFT)); + OUT_CS(((fb->width + 1440-1) << R300_SCISSORS_X_SHIFT) | + ((fb->height + 1440-1) << R300_SCISSORS_Y_SHIFT)); + } + + /* Flush CB & ZB caches and wait until the 3D engine is idle and clean. */ + OUT_CS_TABLE(gpuflush->cb_flush_clean, 6); + END_CS; +} + +void r300_emit_aa_state(struct r300_context *r300, unsigned size, void *state) +{ + struct r300_aa_state *aa = (struct r300_aa_state*)state; + CS_LOCALS(r300); + + BEGIN_CS(size); + OUT_CS_REG(R300_GB_AA_CONFIG, aa->aa_config); + + if (aa->dest) { + OUT_CS_REG_SEQ(R300_RB3D_AARESOLVE_OFFSET, 1); + OUT_CS_RELOC(aa->dest->buffer, aa->dest->offset, 0, aa->dest->domain, 0); + + OUT_CS_REG_SEQ(R300_RB3D_AARESOLVE_PITCH, 1); + OUT_CS_RELOC(aa->dest->buffer, aa->dest->pitch, 0, aa->dest->domain, 0); + } + + OUT_CS_REG(R300_RB3D_AARESOLVE_CTL, aa->aaresolve_ctl); + END_CS; +} + void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state) { struct pipe_framebuffer_state* fb = (struct pipe_framebuffer_state*)state; - struct r300_texture* tex; - struct pipe_surface* surf; - int i; + struct r300_surface* surf; + unsigned i; CS_LOCALS(r300); BEGIN_CS(size); - /* Flush and free renderbuffer caches. */ - OUT_CS_REG(R300_RB3D_DSTCACHE_CTLSTAT, - R300_RB3D_DSTCACHE_CTLSTAT_DC_FREE_FREE_3D_TAGS | - R300_RB3D_DSTCACHE_CTLSTAT_DC_FLUSH_FLUSH_DIRTY_3D); - OUT_CS_REG(R300_ZB_ZCACHE_CTLSTAT, - R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE | - R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE); - - /* Set the number of colorbuffers. */ - if (fb->nr_cbufs > 1) { - if (r300->screen->caps.is_r500) { - OUT_CS_REG(R300_RB3D_CCTL, - R300_RB3D_CCTL_NUM_MULTIWRITES(fb->nr_cbufs) | - R300_RB3D_CCTL_INDEPENDENT_COLORFORMAT_ENABLE_ENABLE); - } else { - OUT_CS_REG(R300_RB3D_CCTL, - R300_RB3D_CCTL_NUM_MULTIWRITES(fb->nr_cbufs)); - } + /* NUM_MULTIWRITES replicates COLOR[0] to all colorbuffers, which is not + * what we usually want. */ + if (r300->screen->caps.is_r500) { + OUT_CS_REG(R300_RB3D_CCTL, + R300_RB3D_CCTL_INDEPENDENT_COLORFORMAT_ENABLE_ENABLE); } else { - OUT_CS_REG(R300_RB3D_CCTL, 0x0); + OUT_CS_REG(R300_RB3D_CCTL, 0); } /* Set up colorbuffers. */ for (i = 0; i < fb->nr_cbufs; i++) { - surf = fb->cbufs[i]; - tex = r300_texture(surf->texture); - assert(tex && tex->buffer && "cbuf is marked, but NULL!"); + surf = r300_surface(fb->cbufs[i]); OUT_CS_REG_SEQ(R300_RB3D_COLOROFFSET0 + (4 * i), 1); - OUT_CS_TEX_RELOC(tex, surf->offset, 0, tex->domain, 0); + OUT_CS_RELOC(surf->buffer, surf->offset, 0, surf->domain, 0); OUT_CS_REG_SEQ(R300_RB3D_COLORPITCH0 + (4 * i), 1); - OUT_CS_TEX_RELOC(tex, tex->fb_state.colorpitch[surf->level], - 0, tex->domain, 0); - - OUT_CS_REG(R300_US_OUT_FMT_0 + (4 * i), tex->fb_state.us_out_fmt); - } - for (; i < 4; i++) { - OUT_CS_REG(R300_US_OUT_FMT_0 + (4 * i), R300_US_OUT_FMT_UNUSED); + OUT_CS_RELOC(surf->buffer, surf->pitch, 0, surf->domain, 0); } /* Set up a zbuffer. */ if (fb->zsbuf) { - surf = fb->zsbuf; - tex = r300_texture(surf->texture); - assert(tex && tex->buffer && "zsbuf is marked, but NULL!"); + surf = r300_surface(fb->zsbuf); - OUT_CS_REG_SEQ(R300_ZB_DEPTHOFFSET, 1); - OUT_CS_TEX_RELOC(tex, surf->offset, 0, tex->domain, 0); + OUT_CS_REG(R300_ZB_FORMAT, surf->format); - OUT_CS_REG(R300_ZB_FORMAT, tex->fb_state.zb_format); + OUT_CS_REG_SEQ(R300_ZB_DEPTHOFFSET, 1); + OUT_CS_RELOC(surf->buffer, surf->offset, 0, surf->domain, 0); OUT_CS_REG_SEQ(R300_ZB_DEPTHPITCH, 1); - OUT_CS_TEX_RELOC(tex, tex->fb_state.depthpitch[surf->level], - 0, tex->domain, 0); + OUT_CS_RELOC(surf->buffer, surf->pitch, 0, surf->domain, 0); + + /* HiZ RAM. */ + if (r300->screen->caps.has_hiz) { + OUT_CS_REG(R300_ZB_HIZ_OFFSET, 0); + OUT_CS_REG(R300_ZB_HIZ_PITCH, 0); + } + + /* Z Mask RAM. (compressed zbuffer) */ + OUT_CS_REG(R300_ZB_ZMASK_OFFSET, 0); + OUT_CS_REG(R300_ZB_ZMASK_PITCH, 0); } - OUT_CS_REG_SEQ(R300_SC_SCISSORS_TL, 2); - if (r300->screen->caps.is_r500) { - OUT_CS(0); - OUT_CS(((fb->width - 1) << R300_SCISSORS_X_SHIFT) | - ((fb->height - 1) << R300_SCISSORS_Y_SHIFT)); - } else { - OUT_CS((1440 << R300_SCISSORS_X_SHIFT) | - (1440 << R300_SCISSORS_Y_SHIFT)); - OUT_CS(((fb->width + 1440-1) << R300_SCISSORS_X_SHIFT) | - ((fb->height + 1440-1) << R300_SCISSORS_Y_SHIFT)); + END_CS; +} + +void r300_emit_hyperz_state(struct r300_context *r300, + unsigned size, void *state) +{ + CS_LOCALS(r300); + WRITE_CS_TABLE(state, size); +} + +void r300_emit_fb_state_pipelined(struct r300_context *r300, + unsigned size, void *state) +{ + struct pipe_framebuffer_state* fb = + (struct pipe_framebuffer_state*)r300->fb_state.state; + unsigned i; + CS_LOCALS(r300); + + BEGIN_CS(size); + + /* Colorbuffer format in the US block. + * (must be written after unpipelined regs) */ + OUT_CS_REG_SEQ(R300_US_OUT_FMT_0, 4); + for (i = 0; i < fb->nr_cbufs; i++) { + OUT_CS(r300_surface(fb->cbufs[i])->format); + } + for (; i < 4; i++) { + OUT_CS(R300_US_OUT_FMT_UNUSED); + } + + /* Multisampling. Depends on framebuffer sample count. + * These are pipelined regs and as such cannot be moved + * to the AA state. */ + if (r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0)) { + unsigned mspos0 = 0x66666666; + unsigned mspos1 = 0x6666666; + + if (fb->nr_cbufs && fb->cbufs[0]->texture->nr_samples > 1) { + /* Subsample placement. These may not be optimal. */ + switch (fb->cbufs[0]->texture->nr_samples) { + case 2: + mspos0 = 0x33996633; + mspos1 = 0x6666663; + break; + case 3: + mspos0 = 0x33936933; + mspos1 = 0x6666663; + break; + case 4: + mspos0 = 0x33939933; + mspos1 = 0x3966663; + break; + case 6: + mspos0 = 0x22a2aa22; + mspos1 = 0x2a65672; + break; + default: + debug_printf("r300: Bad number of multisamples!\n"); + } + } + + OUT_CS_REG_SEQ(R300_GB_MSPOS0, 2); + OUT_CS(mspos0); + OUT_CS(mspos1); } END_CS; } @@ -544,13 +452,14 @@ void r300_emit_query_start(struct r300_context *r300, unsigned size, void*state) OUT_CS_REG(R300_ZB_ZPASS_DATA, 0); END_CS; query->begin_emitted = TRUE; + query->flushed = FALSE; } - static void r300_emit_query_end_frag_pipes(struct r300_context *r300, struct r300_query *query) { struct r300_capabilities* caps = &r300->screen->caps; + struct r300_winsys_buffer *buf = r300->query_current->buffer; CS_LOCALS(r300); assert(caps->num_frag_pipes); @@ -569,28 +478,28 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, /* pipe 3 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 3); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 3), - 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, (query->num_results + 3) * 4, + 0, query->domain, 0); case 3: /* pipe 2 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 2); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 2), - 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, (query->num_results + 2) * 4, + 0, query->domain, 0); case 2: /* pipe 1 only */ /* As mentioned above, accomodate RV380 and older. */ OUT_CS_REG(R300_SU_REG_DEST, 1 << (caps->high_second_pipe ? 3 : 1)); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 1), - 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, (query->num_results + 1) * 4, + 0, query->domain, 0); case 1: /* pipe 0 only */ OUT_CS_REG(R300_SU_REG_DEST, 1 << 0); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset + (sizeof(uint32_t) * 0), - 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, (query->num_results + 0) * 4, + 0, query->domain, 0); break; default: fprintf(stderr, "r300: Implementation error: Chipset reports %d" @@ -606,12 +515,13 @@ static void r300_emit_query_end_frag_pipes(struct r300_context *r300, static void rv530_emit_query_end_single_z(struct r300_context *r300, struct r300_query *query) { + struct r300_winsys_buffer *buf = r300->query_current->buffer; CS_LOCALS(r300); BEGIN_CS(8); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_0); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset, 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, query->num_results * 4, 0, query->domain, 0); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_ALL); END_CS; } @@ -619,15 +529,16 @@ static void rv530_emit_query_end_single_z(struct r300_context *r300, static void rv530_emit_query_end_double_z(struct r300_context *r300, struct r300_query *query) { + struct r300_winsys_buffer *buf = r300->query_current->buffer; CS_LOCALS(r300); BEGIN_CS(14); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_0); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset, 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, (query->num_results + 0) * 4, 0, query->domain, 0); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_1); OUT_CS_REG_SEQ(R300_ZB_ZPASS_ADDR, 1); - OUT_CS_BUF_RELOC(r300->oqbo, query->offset + sizeof(uint32_t), 0, r300_buffer(r300->oqbo)->domain, 0); + OUT_CS_RELOC(buf, (query->num_results + 1) * 4, 0, query->domain, 0); OUT_CS_REG(RV530_FG_ZBREG_DEST, RV530_FG_ZBREG_DEST_PIPE_SELECT_ALL); END_CS; } @@ -652,57 +563,36 @@ void r300_emit_query_end(struct r300_context* r300) r300_emit_query_end_frag_pipes(r300, query); query->begin_emitted = FALSE; + query->num_results += query->num_pipes; + + /* XXX grab all the results and reset the counter. */ + if (query->num_results >= query->buffer_size / 4 - 4) { + query->num_results = (query->buffer_size / 4) / 2; + fprintf(stderr, "r300: Rewinding OQBO...\n"); + } +} + +void r300_emit_invariant_state(struct r300_context *r300, + unsigned size, void *state) +{ + CS_LOCALS(r300); + WRITE_CS_TABLE(state, size); } void r300_emit_rs_state(struct r300_context* r300, unsigned size, void* state) { - struct r300_rs_state* rs = (struct r300_rs_state*)state; - float scale, offset; + struct r300_rs_state* rs = state; CS_LOCALS(r300); BEGIN_CS(size); - OUT_CS_REG(R300_VAP_CNTL_STATUS, rs->vap_control_status); - - OUT_CS_REG(R300_GB_AA_CONFIG, rs->antialiasing_config); - - OUT_CS_REG(R300_GA_POINT_SIZE, rs->point_size); - OUT_CS_REG_SEQ(R300_GA_POINT_MINMAX, 2); - OUT_CS(rs->point_minmax); - OUT_CS(rs->line_control); - + OUT_CS_TABLE(rs->cb_main, 25); if (rs->polygon_offset_enable) { - scale = rs->depth_scale * 12; - offset = rs->depth_offset; - - switch (r300->zbuffer_bpp) { - case 16: - offset *= 4; - break; - case 24: - offset *= 2; - break; + if (r300->zbuffer_bpp == 16) { + OUT_CS_TABLE(rs->cb_poly_offset_zb16, 5); + } else { + OUT_CS_TABLE(rs->cb_poly_offset_zb24, 5); } - - OUT_CS_REG_SEQ(R300_SU_POLY_OFFSET_FRONT_SCALE, 4); - OUT_CS_32F(scale); - OUT_CS_32F(offset); - OUT_CS_32F(scale); - OUT_CS_32F(offset); } - - OUT_CS_REG_SEQ(R300_SU_POLY_OFFSET_ENABLE, 2); - OUT_CS(rs->polygon_offset_enable); - OUT_CS(rs->cull_mode); - OUT_CS_REG(R300_GA_LINE_STIPPLE_CONFIG, rs->line_stipple_config); - OUT_CS_REG(R300_GA_LINE_STIPPLE_VALUE, rs->line_stipple_value); - OUT_CS_REG(R300_GA_POLY_MODE, rs->polygon_mode); - OUT_CS_REG(R300_SC_CLIP_RULE, rs->clip_rule); - OUT_CS_REG(R300_GB_ENABLE, rs->stuffing_enable); - OUT_CS_REG_SEQ(R300_GA_POINT_S0, 4); - OUT_CS_32F(rs->point_texcoord_left); - OUT_CS_32F(rs->point_texcoord_bottom); - OUT_CS_32F(rs->point_texcoord_right); - OUT_CS_32F(rs->point_texcoord_top); END_CS; } @@ -717,9 +607,18 @@ void r300_emit_rs_block_state(struct r300_context* r300, if (SCREEN_DBG_ON(r300->screen, DBG_DRAW)) { r500_dump_rs_block(rs); - } - DBG(r300, DBG_DRAW, "r300: RS emit:\n"); + fprintf(stderr, "r300: RS emit:\n"); + + for (i = 0; i < count; i++) + fprintf(stderr, " : ip %d: 0x%08x\n", i, rs->ip[i]); + + for (i = 0; i < count; i++) + fprintf(stderr, " : inst %d: 0x%08x\n", i, rs->inst[i]); + + fprintf(stderr, " : count: 0x%08x inst_count: 0x%08x\n", + rs->count, rs->inst_count); + } BEGIN_CS(size); OUT_CS_REG_SEQ(R300_VAP_VTX_STATE_CNTL, 2); @@ -735,9 +634,6 @@ void r300_emit_rs_block_state(struct r300_context* r300, OUT_CS_REG_SEQ(R300_RS_IP_0, count); } OUT_CS_TABLE(rs->ip, count); - for (i = 0; i < count; i++) { - DBG(r300, DBG_DRAW, " : ip %d: 0x%08x\n", i, rs->ip[i]); - } OUT_CS_REG_SEQ(R300_RS_COUNT, 2); OUT_CS(rs->count); @@ -749,13 +645,6 @@ void r300_emit_rs_block_state(struct r300_context* r300, OUT_CS_REG_SEQ(R300_RS_INST_0, count); } OUT_CS_TABLE(rs->inst, count); - for (i = 0; i < count; i++) { - DBG(r300, DBG_DRAW, " : inst %d: 0x%08x\n", i, rs->inst[i]); - } - - DBG(r300, DBG_DRAW, " : count: 0x%08x inst_count: 0x%08x\n", - rs->count, rs->inst_count); - END_CS; } @@ -821,19 +710,11 @@ void r300_emit_aos(struct r300_context* r300, int offset, boolean indexed) struct pipe_vertex_element *velem = r300->velems->velem; struct r300_buffer *buf; int i; + unsigned *hw_format_size = r300->velems->hw_format_size; unsigned size1, size2, aos_count = r300->velems->count; unsigned packet_size = (aos_count * 3 + 1) / 2; CS_LOCALS(r300); - for (i = 0; i < aos_count; i++) { - if ((vbuf[velem[i].vertex_buffer_index].buffer_offset + velem[i].src_offset) % 4 != 0) { - /* XXX We must align the buffer. */ - assert(0); - fprintf(stderr, "r300: Unaligned vertex buffer offsets aren't supported, aborting..\n"); - abort(); - } - } - BEGIN_CS(2 + packet_size + aos_count * 2); OUT_CS_PKT3(R300_PACKET3_3D_LOAD_VBPNTR, packet_size); OUT_CS(aos_count | (!indexed ? R300_VC_FORCE_PREFETCH : 0)); @@ -841,8 +722,8 @@ void r300_emit_aos(struct r300_context* r300, int offset, boolean indexed) for (i = 0; i < aos_count - 1; i += 2) { vb1 = &vbuf[velem[i].vertex_buffer_index]; vb2 = &vbuf[velem[i+1].vertex_buffer_index]; - size1 = util_format_get_blocksize(velem[i].src_format); - size2 = util_format_get_blocksize(velem[i+1].src_format); + size1 = hw_format_size[i]; + size2 = hw_format_size[i+1]; OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(vb1->stride) | R300_VBPNTR_SIZE1(size2) | R300_VBPNTR_STRIDE1(vb2->stride)); @@ -852,7 +733,7 @@ void r300_emit_aos(struct r300_context* r300, int offset, boolean indexed) if (aos_count & 1) { vb1 = &vbuf[velem[i].vertex_buffer_index]; - size1 = util_format_get_blocksize(velem[i].src_format); + size1 = hw_format_size[i]; OUT_CS(R300_VBPNTR_SIZE0(size1) | R300_VBPNTR_STRIDE0(vb1->stride)); OUT_CS(vb1->buffer_offset + velem[i].src_offset + offset * vb1->stride); @@ -897,21 +778,25 @@ void r300_emit_vertex_stream_state(struct r300_context* r300, unsigned i; CS_LOCALS(r300); - DBG(r300, DBG_DRAW, "r300: PSC emit:\n"); + if (DBG_ON(r300, DBG_DRAW)) { + fprintf(stderr, "r300: PSC emit:\n"); + + for (i = 0; i < streams->count; i++) { + fprintf(stderr, " : prog_stream_cntl%d: 0x%08x\n", i, + streams->vap_prog_stream_cntl[i]); + } + + for (i = 0; i < streams->count; i++) { + fprintf(stderr, " : prog_stream_cntl_ext%d: 0x%08x\n", i, + streams->vap_prog_stream_cntl_ext[i]); + } + } BEGIN_CS(size); OUT_CS_REG_SEQ(R300_VAP_PROG_STREAM_CNTL_0, streams->count); OUT_CS_TABLE(streams->vap_prog_stream_cntl, streams->count); - for (i = 0; i < streams->count; i++) { - DBG(r300, DBG_DRAW, " : prog_stream_cntl%d: 0x%08x\n", i, - streams->vap_prog_stream_cntl[i]); - } OUT_CS_REG_SEQ(R300_VAP_PROG_STREAM_CNTL_EXT_0, streams->count); OUT_CS_TABLE(streams->vap_prog_stream_cntl_ext, streams->count); - for (i = 0; i < streams->count; i++) { - DBG(r300, DBG_DRAW, " : prog_stream_cntl_ext%d: 0x%08x\n", i, - streams->vap_prog_stream_cntl_ext[i]); - } END_CS; } @@ -924,6 +809,13 @@ void r300_emit_pvs_flush(struct r300_context* r300, unsigned size, void* state) END_CS; } +void r300_emit_vap_invariant_state(struct r300_context *r300, + unsigned size, void *state) +{ + CS_LOCALS(r300); + WRITE_CS_TABLE(state, size); +} + void r300_emit_vs_state(struct r300_context* r300, unsigned size, void* state) { struct r300_vertex_shader* vs = (struct r300_vertex_shader*)state; @@ -948,6 +840,7 @@ void r300_emit_vs_state(struct r300_context* r300, unsigned size, void* state) CS_LOCALS(r300); BEGIN_CS(size); + /* R300_VAP_PVS_CODE_CNTL_0 * R300_VAP_PVS_CONST_CNTL * R300_VAP_PVS_CODE_CNTL_1 @@ -1012,12 +905,7 @@ void r300_emit_viewport_state(struct r300_context* r300, BEGIN_CS(size); OUT_CS_REG_SEQ(R300_SE_VPORT_XSCALE, 6); - OUT_CS_32F(viewport->xscale); - OUT_CS_32F(viewport->xoffset); - OUT_CS_32F(viewport->yscale); - OUT_CS_32F(viewport->yoffset); - OUT_CS_32F(viewport->zscale); - OUT_CS_32F(viewport->zoffset); + OUT_CS_TABLE(&viewport->xscale, 6); OUT_CS_REG(R300_VAP_VTE_CNTL, viewport->vte_control); END_CS; } @@ -1099,10 +987,9 @@ validate: } } /* ...occlusion query buffer... */ - if (r300->query_start.dirty || - (r300->query_current && r300->query_current->begin_emitted)) { - if (!r300_add_buffer(r300->rws, r300->oqbo, - 0, r300_buffer(r300->oqbo)->domain)) { + if (r300->query_current) { + if (!r300->rws->add_buffer(r300->rws, r300->query_current->buffer, + 0, r300->query_current->domain)) { r300->context.flush(&r300->context, 0, NULL); goto validate; } diff --git a/src/gallium/drivers/r300/r300_emit.h b/src/gallium/drivers/r300/r300_emit.h index 90660883423..586ccda620b 100644 --- a/src/gallium/drivers/r300/r300_emit.h +++ b/src/gallium/drivers/r300/r300_emit.h @@ -29,6 +29,8 @@ struct rX00_fragment_program_code; struct r300_vertex_program_code; +uint32_t pack_float24(float f); + void r300_emit_aos(struct r300_context* r300, int offset, boolean indexed); void r300_emit_blend_state(struct r300_context* r300, @@ -43,16 +45,12 @@ void r300_emit_clip_state(struct r300_context* r300, void r300_emit_dsa_state(struct r300_context* r300, unsigned size, void* state); -unsigned r300_get_fs_atom_size(struct r300_context *r300); - void r300_emit_fs(struct r300_context* r300, unsigned size, void *state); void r300_emit_fs_constants(struct r300_context* r300, unsigned size, void *state); void r300_emit_fs_rc_constant_state(struct r300_context* r300, unsigned size, void *state); -unsigned r500_get_fs_atom_size(struct r300_context *r300); - void r500_emit_fs(struct r300_context* r300, unsigned size, void *state); void r500_emit_fs_constants(struct r300_context* r300, unsigned size, void *state); @@ -61,6 +59,16 @@ void r500_emit_fs_rc_constant_state(struct r300_context* r300, unsigned size, vo void r300_emit_fb_state(struct r300_context* r300, unsigned size, void* state); +void r300_emit_fb_state_pipelined(struct r300_context *r300, + unsigned size, void *state); + +void r300_emit_gpu_flush(struct r300_context *r300, unsigned size, void *state); + +void r300_emit_hyperz_state(struct r300_context *r300, + unsigned size, void *state); + +void r300_emit_aa_state(struct r300_context *r300, unsigned size, void *state); + void r300_emit_query_start(struct r300_context *r300, unsigned size, void *state); void r300_emit_query_end(struct r300_context* r300); @@ -78,6 +86,9 @@ void r300_emit_textures_state(struct r300_context *r300, void r300_emit_aos_swtcl(struct r300_context *r300, boolean indexed); +void r300_emit_vap_invariant_state(struct r300_context *r300, + unsigned size, void *state); + void r300_emit_vertex_stream_state(struct r300_context* r300, unsigned size, void* state); @@ -96,6 +107,9 @@ void r300_emit_pvs_flush(struct r300_context* r300, unsigned size, void* state); void r300_emit_texture_cache_inval(struct r300_context* r300, unsigned size, void* state); +void r300_emit_invariant_state(struct r300_context *r300, + unsigned size, void *state); + unsigned r300_get_num_dirty_dwords(struct r300_context *r300); /* Emit all dirty state. */ diff --git a/src/gallium/drivers/r300/r300_flush.c b/src/gallium/drivers/r300/r300_flush.c index 360b19a0c1e..ba840bfff81 100644 --- a/src/gallium/drivers/r300/r300_flush.c +++ b/src/gallium/drivers/r300/r300_flush.c @@ -39,8 +39,6 @@ static void r300_flush(struct pipe_context* pipe, struct r300_atom *atom; struct r300_fence **rfence = (struct r300_fence**)fence; - CS_LOCALS(r300); - (void) cs_count; /* We probably need to flush Draw, but we may have been called from * within Draw. This feels kludgy, but it might be the best thing. * @@ -52,7 +50,10 @@ static void r300_flush(struct pipe_context* pipe, if (r300->dirty_hw) { r300_emit_query_end(r300); - FLUSH_CS; + if (SCREEN_DBG_ON(r300->screen, DBG_STATS)) { + r300->flush_counter++; + } + r300->rws->flush_cs(r300->rws); r300->dirty_hw = 0; /* New kitchen sink, baby. */ diff --git a/src/gallium/drivers/r300/r300_fs.c b/src/gallium/drivers/r300/r300_fs.c index a434808046c..424f831731d 100644 --- a/src/gallium/drivers/r300/r300_fs.c +++ b/src/gallium/drivers/r300/r300_fs.c @@ -28,7 +28,9 @@ #include "tgsi/tgsi_dump.h" #include "tgsi/tgsi_ureg.h" +#include "r300_cb.h" #include "r300_context.h" +#include "r300_emit.h" #include "r300_screen.h" #include "r300_fs.h" #include "r300_reg.h" @@ -229,6 +231,122 @@ static void r300_dummy_fragment_shader( ureg_destroy(ureg); } +static void r300_emit_fs_code_to_buffer( + struct r300_context *r300, + struct r300_fragment_shader_code *shader) +{ + struct rX00_fragment_program_code *generic_code = &shader->code; + unsigned imm_count = shader->immediates_count; + unsigned imm_first = shader->externals_count; + unsigned imm_end = generic_code->constants.Count; + struct rc_constant *constants = generic_code->constants.Constants; + unsigned i; + CB_LOCALS; + + if (r300->screen->caps.is_r500) { + struct r500_fragment_program_code *code = &generic_code->code.r500; + + shader->cb_code_size = 17 + + ((code->inst_end + 1) * 6) + + imm_count * 7; + + NEW_CB(shader->cb_code, shader->cb_code_size); + OUT_CB_REG(R500_US_CONFIG, R500_ZERO_TIMES_ANYTHING_EQUALS_ZERO); + OUT_CB_REG(R500_US_PIXSIZE, code->max_temp_idx); + OUT_CB_REG(R500_US_CODE_RANGE, + R500_US_CODE_RANGE_ADDR(0) | R500_US_CODE_RANGE_SIZE(code->inst_end)); + OUT_CB_REG(R500_US_CODE_OFFSET, 0); + OUT_CB_REG(R500_US_CODE_ADDR, + R500_US_CODE_START_ADDR(0) | R500_US_CODE_END_ADDR(code->inst_end)); + + OUT_CB_REG(R500_GA_US_VECTOR_INDEX, R500_GA_US_VECTOR_INDEX_TYPE_INSTR); + OUT_CB_ONE_REG(R500_GA_US_VECTOR_DATA, (code->inst_end + 1) * 6); + for (i = 0; i <= code->inst_end; i++) { + OUT_CB(code->inst[i].inst0); + OUT_CB(code->inst[i].inst1); + OUT_CB(code->inst[i].inst2); + OUT_CB(code->inst[i].inst3); + OUT_CB(code->inst[i].inst4); + OUT_CB(code->inst[i].inst5); + } + + /* Emit immediates. */ + if (imm_count) { + for(i = imm_first; i < imm_end; ++i) { + if (constants[i].Type == RC_CONSTANT_IMMEDIATE) { + const float *data = constants[i].u.Immediate; + + OUT_CB_REG(R500_GA_US_VECTOR_INDEX, + R500_GA_US_VECTOR_INDEX_TYPE_CONST | + (i & R500_GA_US_VECTOR_INDEX_MASK)); + OUT_CB_ONE_REG(R500_GA_US_VECTOR_DATA, 4); + OUT_CB_TABLE(data, 4); + } + } + } + } else { /* r300 */ + struct r300_fragment_program_code *code = &generic_code->code.r300; + + shader->cb_code_size = 19 + + (r300->screen->caps.is_r400 ? 2 : 0) + + code->alu.length * 4 + + (code->tex.length ? (1 + code->tex.length) : 0) + + imm_count * 5; + + NEW_CB(shader->cb_code, shader->cb_code_size); + + if (r300->screen->caps.is_r400) + OUT_CB_REG(R400_US_CODE_BANK, 0); + + OUT_CB_REG(R300_US_CONFIG, code->config); + OUT_CB_REG(R300_US_PIXSIZE, code->pixsize); + OUT_CB_REG(R300_US_CODE_OFFSET, code->code_offset); + + OUT_CB_REG_SEQ(R300_US_CODE_ADDR_0, 4); + OUT_CB_TABLE(code->code_addr, 4); + + OUT_CB_REG_SEQ(R300_US_ALU_RGB_INST_0, code->alu.length); + for (i = 0; i < code->alu.length; i++) + OUT_CB(code->alu.inst[i].rgb_inst); + + OUT_CB_REG_SEQ(R300_US_ALU_RGB_ADDR_0, code->alu.length); + for (i = 0; i < code->alu.length; i++) + OUT_CB(code->alu.inst[i].rgb_addr); + + OUT_CB_REG_SEQ(R300_US_ALU_ALPHA_INST_0, code->alu.length); + for (i = 0; i < code->alu.length; i++) + OUT_CB(code->alu.inst[i].alpha_inst); + + OUT_CB_REG_SEQ(R300_US_ALU_ALPHA_ADDR_0, code->alu.length); + for (i = 0; i < code->alu.length; i++) + OUT_CB(code->alu.inst[i].alpha_addr); + + if (code->tex.length) { + OUT_CB_REG_SEQ(R300_US_TEX_INST_0, code->tex.length); + OUT_CB_TABLE(code->tex.inst, code->tex.length); + } + + /* Emit immediates. */ + if (imm_count) { + for(i = imm_first; i < imm_end; ++i) { + if (constants[i].Type == RC_CONSTANT_IMMEDIATE) { + const float *data = constants[i].u.Immediate; + + OUT_CB_REG_SEQ(R300_PFS_PARAM_0_X + i * 16, 4); + OUT_CB(pack_float24(data[0])); + OUT_CB(pack_float24(data[1])); + OUT_CB(pack_float24(data[2])); + OUT_CB(pack_float24(data[3])); + } + } + } + } + + OUT_CB_REG(R300_FG_DEPTH_SRC, shader->fg_depth_src); + OUT_CB_REG(R300_US_W_FMT, shader->us_out_w); + END_CB; +} + static void r300_translate_fragment_shader( struct r300_context* r300, struct r300_fragment_shader_code* shader, @@ -338,6 +456,9 @@ static void r300_translate_fragment_shader( /* And, finally... */ rc_destroy(&compiler.Base); + + /* Build the command buffer. */ + r300_emit_fs_code_to_buffer(r300, shader); } boolean r300_pick_fragment_shader(struct r300_context* r300) diff --git a/src/gallium/drivers/r300/r300_fs.h b/src/gallium/drivers/r300/r300_fs.h index 1cc43553595..51bfa88c5ef 100644 --- a/src/gallium/drivers/r300/r300_fs.h +++ b/src/gallium/drivers/r300/r300_fs.h @@ -50,6 +50,9 @@ struct r300_fragment_shader_code { struct r300_fragment_program_external_state compare_state; struct rX00_fragment_program_code code; + unsigned cb_code_size; + uint32_t *cb_code; + struct r300_fragment_shader_code* next; }; diff --git a/src/gallium/drivers/r300/r300_hyperz.c b/src/gallium/drivers/r300/r300_hyperz.c index b41b6b1508d..e5c76589528 100644 --- a/src/gallium/drivers/r300/r300_hyperz.c +++ b/src/gallium/drivers/r300/r300_hyperz.c @@ -31,33 +31,46 @@ /* The ZTOP state */ /*****************************************************************************/ -static boolean r300_dsa_writes_depth_stencil(struct r300_dsa_state* dsa) +static boolean r300_dsa_writes_stencil( + struct pipe_stencil_state *s) { - /* We are interested only in the cases when a new depth or stencil value - * can be written and changed. */ + return s->enabled && s->writemask && + (s->fail_op != PIPE_STENCIL_OP_KEEP || + s->zfail_op != PIPE_STENCIL_OP_KEEP || + s->zpass_op != PIPE_STENCIL_OP_KEEP); +} + +static boolean r300_dsa_writes_depth_stencil( + struct pipe_depth_stencil_alpha_state *dsa) +{ + /* We are interested only in the cases when a depth or stencil value + * can be changed. */ + + if (dsa->depth.enabled && dsa->depth.writemask && + dsa->depth.func != PIPE_FUNC_NEVER) + return TRUE; + + if (r300_dsa_writes_stencil(&dsa->stencil[0]) || + r300_dsa_writes_stencil(&dsa->stencil[1])) + return TRUE; - /* We might optionally check for [Z func: never] and inspect the stencil - * state in a similar fashion, but it's not terribly important. */ - return (dsa->z_buffer_control & R300_Z_WRITE_ENABLE) || - (dsa->stencil_ref_mask & R300_STENCILWRITEMASK_MASK) || - ((dsa->z_buffer_control & R500_STENCIL_REFMASK_FRONT_BACK) && - (dsa->stencil_ref_bf & R300_STENCILWRITEMASK_MASK)); + return FALSE; } -static boolean r300_dsa_alpha_test_enabled(struct r300_dsa_state* dsa) +static boolean r300_dsa_alpha_test_enabled( + struct pipe_depth_stencil_alpha_state *dsa) { /* We are interested only in the cases when alpha testing can kill * a fragment. */ - uint32_t af = dsa->alpha_function; - return (af & R300_FG_ALPHA_FUNC_ENABLE) && - (af & R300_FG_ALPHA_FUNC_ALWAYS) != R300_FG_ALPHA_FUNC_ALWAYS; + return dsa->alpha.enabled && dsa->alpha.func != PIPE_FUNC_ALWAYS; } static void r300_update_ztop(struct r300_context* r300) { struct r300_ztop_state* ztop_state = (struct r300_ztop_state*)r300->ztop_state.state; + uint32_t old_ztop = ztop_state->z_buffer_top; /* This is important enough that I felt it warranted a comment. * @@ -99,7 +112,8 @@ static void r300_update_ztop(struct r300_context* r300) ztop_state->z_buffer_top = R300_ZTOP_ENABLE; } - r300->ztop_state.dirty = TRUE; + if (ztop_state->z_buffer_top != old_ztop) + r300->ztop_state.dirty = TRUE; } void r300_update_hyperz_state(struct r300_context* r300) diff --git a/src/gallium/drivers/r300/r300_query.c b/src/gallium/drivers/r300/r300_query.c index 97081c4a00f..10086ee9256 100644 --- a/src/gallium/drivers/r300/r300_query.c +++ b/src/gallium/drivers/r300/r300_query.c @@ -26,6 +26,7 @@ #include "r300_context.h" #include "r300_screen.h" #include "r300_emit.h" +#include "r300_winsys.h" #include <stdio.h> @@ -34,30 +35,29 @@ static struct pipe_query *r300_create_query(struct pipe_context *pipe, { struct r300_context *r300 = r300_context(pipe); struct r300_screen *r300screen = r300->screen; - unsigned query_size; - struct r300_query *q, *qptr; + struct r300_query *q; + + if (query_type != PIPE_QUERY_OCCLUSION_COUNTER) { + return NULL; + } q = CALLOC_STRUCT(r300_query); + if (!q) + return NULL; q->type = query_type; - assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER); + q->domain = R300_DOMAIN_GTT; + q->buffer_size = 4096; if (r300screen->caps.family == CHIP_FAMILY_RV530) - query_size = r300screen->caps.num_z_pipes * sizeof(uint32_t); + q->num_pipes = r300screen->caps.num_z_pipes; else - query_size = r300screen->caps.num_frag_pipes * sizeof(uint32_t); + q->num_pipes = r300screen->caps.num_frag_pipes; - if (!is_empty_list(&r300->query_list)) { - qptr = last_elem(&r300->query_list); - q->offset = qptr->offset + query_size; - } insert_at_tail(&r300->query_list, q); - /* XXX */ - if (q->offset >= 4096) { - q->offset = 0; - fprintf(stderr, "r300: Rewinding OQBO...\n"); - } + /* Open up the occlusion query buffer. */ + q->buffer = r300->rws->buffer_create(r300->rws, 4096, 0, q->domain, q->buffer_size); return (struct pipe_query*)q; } @@ -65,18 +65,26 @@ static struct pipe_query *r300_create_query(struct pipe_context *pipe, static void r300_destroy_query(struct pipe_context* pipe, struct pipe_query* query) { - struct r300_query* q = (struct r300_query*)query; + struct r300_context *r300 = r300_context(pipe); + struct r300_query* q = r300_query(query); + r300->rws->buffer_reference(r300->rws, &q->buffer, NULL); remove_from_list(q); FREE(query); } +void r300_resume_query(struct r300_context *r300, + struct r300_query *query) +{ + r300->query_current = query; + r300->query_start.dirty = TRUE; +} + static void r300_begin_query(struct pipe_context* pipe, struct pipe_query* query) { - uint32_t value = ~0U; struct r300_context* r300 = r300_context(pipe); - struct r300_query* q = (struct r300_query*)query; + struct r300_query* q = r300_query(query); if (r300->query_current != NULL) { fprintf(stderr, "r300: begin_query: " @@ -85,85 +93,59 @@ static void r300_begin_query(struct pipe_context* pipe, return; } - pipe_buffer_write(pipe, - r300->oqbo, - q->offset, - sizeof value, - &value); + q->num_results = 0; + r300_resume_query(r300, q); +} - q->flushed = FALSE; - r300->query_current = q; - r300->query_start.dirty = TRUE; +void r300_stop_query(struct r300_context *r300) +{ + r300_emit_query_end(r300); + r300->query_current = NULL; } static void r300_end_query(struct pipe_context* pipe, struct pipe_query* query) { struct r300_context* r300 = r300_context(pipe); + struct r300_query *q = r300_query(query); - if ((struct r300_query*)query != r300->query_current) { + if (q != r300->query_current) { fprintf(stderr, "r300: end_query: Got invalid query.\n"); assert(0); return; } - r300_emit_query_end(r300); - r300->query_current = NULL; + r300_stop_query(r300); } static boolean r300_get_query_result(struct pipe_context* pipe, struct pipe_query* query, boolean wait, - uint64_t* result) + void* vresult) { struct r300_context* r300 = r300_context(pipe); - struct r300_screen* r300screen = r300->screen; - struct r300_query *q = (struct r300_query*)query; - struct pipe_transfer *transfer; - unsigned flags = PIPE_TRANSFER_READ; - uint32_t* map; - uint32_t temp = 0; - unsigned i, num_results; - - if (q->flushed == FALSE) + struct r300_query *q = r300_query(query); + unsigned flags, i; + uint32_t temp, *map; + uint64_t *result = (uint64_t*)vresult; + + if (!q->flushed) pipe->flush(pipe, 0, NULL); - if (!wait) { - flags |= PIPE_TRANSFER_DONTBLOCK; - } - map = pipe_buffer_map(pipe, r300->oqbo, flags, &transfer); + flags = PIPE_TRANSFER_READ | (!wait ? PIPE_TRANSFER_DONTBLOCK : 0); + + map = r300->rws->buffer_map(r300->rws, q->buffer, flags); if (!map) return FALSE; - map += q->offset / 4; - if (r300screen->caps.family == CHIP_FAMILY_RV530) - num_results = r300screen->caps.num_z_pipes; - else - num_results = r300screen->caps.num_frag_pipes; - - for (i = 0; i < num_results; i++) { - if (*map == ~0U) { - /* Looks like our results aren't ready yet. */ - if (wait) { - fprintf(stderr, "r300: Despite waiting, OQ results haven't " - "come in yet. This is a driver bug.\n" - "r300: Returning bogus results to avoid " - "a possible infinite loop...\n"); - temp = 987654321; - } else { - temp = ~0U; - } - break; - } + /* Sum up the results. */ + temp = 0; + for (i = 0; i < q->num_results; i++) { temp += *map; map++; } - pipe_buffer_unmap(pipe, r300->oqbo, transfer); - if (temp == ~0U) { - /* Our results haven't been written yet... */ - return FALSE; - } + r300->rws->buffer_unmap(r300->rws, q->buffer); *result = temp; return TRUE; @@ -191,11 +173,61 @@ static void r300_render_condition(struct pipe_context *pipe, } } +/*************************************************************************** + * Fake occlusion queries (for debugging) + ***************************************************************************/ + +static unsigned r300_fake_query; + +static struct pipe_query *r300_fake_create_query(struct pipe_context *pipe, + unsigned query_type) +{ + return (struct pipe_query*)&r300_fake_query; +} + +static void r300_fake_destroy_query(struct pipe_context* pipe, + struct pipe_query* query) +{ +} + +static void r300_fake_begin_query(struct pipe_context* pipe, + struct pipe_query* query) +{ +} + +static void r300_fake_end_query(struct pipe_context* pipe, + struct pipe_query* query) +{ +} + +static boolean r300_fake_get_query_result(struct pipe_context* pipe, + struct pipe_query* query, + boolean wait, void* vresult) +{ + uint64_t *result = (uint64_t*)vresult; + *result = 1000000; + return TRUE; +} + +static void r300_fake_render_condition(struct pipe_context *pipe, + struct pipe_query *query, uint mode) +{ +} + void r300_init_query_functions(struct r300_context* r300) { - r300->context.create_query = r300_create_query; - r300->context.destroy_query = r300_destroy_query; - r300->context.begin_query = r300_begin_query; - r300->context.end_query = r300_end_query; - r300->context.get_query_result = r300_get_query_result; - r300->context.render_condition = r300_render_condition; + if (DBG_ON(r300, DBG_FAKE_OCC)) { + r300->context.create_query = r300_fake_create_query; + r300->context.destroy_query = r300_fake_destroy_query; + r300->context.begin_query = r300_fake_begin_query; + r300->context.end_query = r300_fake_end_query; + r300->context.get_query_result = r300_fake_get_query_result; + r300->context.render_condition = r300_fake_render_condition; + } else { + r300->context.create_query = r300_create_query; + r300->context.destroy_query = r300_destroy_query; + r300->context.begin_query = r300_begin_query; + r300->context.end_query = r300_end_query; + r300->context.get_query_result = r300_get_query_result; + r300->context.render_condition = r300_render_condition; + } } diff --git a/src/gallium/drivers/r300/r300_reg.h b/src/gallium/drivers/r300/r300_reg.h index c4fa19ace53..180560175a4 100644 --- a/src/gallium/drivers/r300/r300_reg.h +++ b/src/gallium/drivers/r300/r300_reg.h @@ -1630,6 +1630,40 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_TX_FORMAT_GAMMA (1 << 21) # define R300_TX_FORMAT_YUV_TO_RGB (1 << 22) +# define R300_TX_CACHE(x) ((x) << 27) +# define R300_TX_CACHE_WHOLE 0 +/* reserved */ +# define R300_TX_CACHE_HALF_0 2 +# define R300_TX_CACHE_HALF_1 3 +# define R300_TX_CACHE_FOURTH_0 4 +# define R300_TX_CACHE_FOURTH_1 5 +# define R300_TX_CACHE_FOURTH_2 6 +# define R300_TX_CACHE_FOURTH_3 7 +# define R300_TX_CACHE_EIGHTH_0 8 +# define R300_TX_CACHE_EIGHTH_1 9 +# define R300_TX_CACHE_EIGHTH_2 10 +# define R300_TX_CACHE_EIGHTH_3 11 +# define R300_TX_CACHE_EIGHTH_4 12 +# define R300_TX_CACHE_EIGHTH_5 13 +# define R300_TX_CACHE_EIGHTH_6 14 +# define R300_TX_CACHE_EIGHTH_7 15 +# define R300_TX_CACHE_SIXTEENTH_0 16 +# define R300_TX_CACHE_SIXTEENTH_1 17 +# define R300_TX_CACHE_SIXTEENTH_2 18 +# define R300_TX_CACHE_SIXTEENTH_3 19 +# define R300_TX_CACHE_SIXTEENTH_4 20 +# define R300_TX_CACHE_SIXTEENTH_5 21 +# define R300_TX_CACHE_SIXTEENTH_6 22 +# define R300_TX_CACHE_SIXTEENTH_7 23 +# define R300_TX_CACHE_SIXTEENTH_8 24 +# define R300_TX_CACHE_SIXTEENTH_9 25 +# define R300_TX_CACHE_SIXTEENTH_10 26 +# define R300_TX_CACHE_SIXTEENTH_11 27 +# define R300_TX_CACHE_SIXTEENTH_12 28 +# define R300_TX_CACHE_SIXTEENTH_13 29 +# define R300_TX_CACHE_SIXTEENTH_14 30 +# define R300_TX_CACHE_SIXTEENTH_15 31 + #define R300_TX_FORMAT2_0 0x4500 /* obvious missing in gap */ # define R300_TX_PITCHMASK_SHIFT 0 # define R300_TX_PITCHMASK_MASK (2047 << 0) @@ -2639,6 +2673,24 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* Z Buffer Clear Value */ #define R300_ZB_DEPTHCLEARVALUE 0x4f28 +/* Z Mask RAM is a Z compression buffer. + * Each dword of the Z Mask contains compression info for 16 4x4 pixel blocks, + * that is 2 bits for each block. + * On chips with 2 Z pipes, every other dword maps to a different pipe. + */ + +/* The dword offset into Z mask RAM (bits 18:4) */ +#define R300_ZB_ZMASK_OFFSET 0x4f30 + +/* Z Mask Pitch. */ +#define R300_ZB_ZMASK_PITCH 0x4f34 + +/* Access to Z Mask RAM in a manner similar to HiZ RAM. + * The indices are autoincrementing. */ +#define R300_ZB_ZMASK_WRINDEX 0x4f38 +#define R300_ZB_ZMASK_DWORD 0x4f3c +#define R300_ZB_ZMASK_RDINDEX 0x4f40 + /* Hierarchical Z Memory Offset */ #define R300_ZB_HIZ_OFFSET 0x4f44 @@ -3437,9 +3489,18 @@ enum { # define RADEON_WAIT_3D_IDLECLEAN (1 << 17) # define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) +#define R200_3D_DRAW_IMMD_2 0xC0003500 + +#define RADEON_CP_PACKET0 0x0 /* XXX stolen from radeon_reg.h */ #define RADEON_CP_PACKET3 0xC0000000 -#define R200_3D_DRAW_IMMD_2 0xC0003500 +#define RADEON_ONE_REG_WR (1 << 15) + +#define CP_PACKET0(register, count) \ + (RADEON_CP_PACKET0 | ((count) << 16) | ((register) >> 2)) + +#define CP_PACKET3(op, count) \ + (RADEON_CP_PACKET3 | (op) | ((count) << 16)) #endif /* _R300_REG_H */ diff --git a/src/gallium/drivers/r300/r300_render.c b/src/gallium/drivers/r300/r300_render.c index 23caaa54730..53728431a63 100644 --- a/src/gallium/drivers/r300/r300_render.c +++ b/src/gallium/drivers/r300/r300_render.c @@ -35,6 +35,7 @@ #include "util/u_prim.h" #include "r300_cs.h" +#include "r300_cb.h" #include "r300_context.h" #include "r300_screen_buffer.h" #include "r300_emit.h" @@ -43,6 +44,8 @@ #include <limits.h> +#define IMMD_DWORDS 32 + static uint32_t r300_translate_primitive(unsigned prim) { switch (prim) { @@ -269,7 +272,7 @@ static boolean immd_is_good_idea(struct r300_context *r300, return FALSE; } - if (count > 10) { + if (count * r300->velems->vertex_size_dwords > IMMD_DWORDS) { return FALSE; } @@ -308,84 +311,75 @@ static void r300_emit_draw_arrays_immediate(struct r300_context *r300, struct pipe_vertex_element* velem; struct pipe_vertex_buffer* vbuf; unsigned vertex_element_count = r300->velems->count; - unsigned i, v, vbi, dw, elem_offset, dwords; + unsigned i, v, vbi, dwords; /* Size of the vertex, in dwords. */ - unsigned vertex_size = 0; - - /* Offsets of the attribute, in dwords, from the start of the vertex. */ - unsigned offset[PIPE_MAX_ATTRIBS]; + unsigned vertex_size = r300->velems->vertex_size_dwords; /* Size of the vertex element, in dwords. */ unsigned size[PIPE_MAX_ATTRIBS]; /* Stride to the same attrib in the next vertex in the vertex buffer, * in dwords. */ - unsigned stride[PIPE_MAX_ATTRIBS] = {0}; + unsigned stride[PIPE_MAX_ATTRIBS]; /* Mapped vertex buffers. */ - uint32_t* map[PIPE_MAX_ATTRIBS] = {0}; - struct pipe_transfer* transfer[PIPE_MAX_ATTRIBS] = {NULL}; + uint32_t* map[PIPE_MAX_ATTRIBS]; + uint32_t* mapelem[PIPE_MAX_ATTRIBS]; + struct pipe_transfer* transfer[PIPE_MAX_ATTRIBS] = {0}; - CS_LOCALS(r300); + CB_LOCALS; /* Calculate the vertex size, offsets, strides etc. and map the buffers. */ for (i = 0; i < vertex_element_count; i++) { velem = &r300->velems->velem[i]; - offset[i] = velem->src_offset / 4; - size[i] = util_format_get_blocksize(velem->src_format) / 4; - vertex_size += size[i]; + size[i] = r300->velems->hw_format_size[i] / 4; vbi = velem->vertex_buffer_index; + vbuf = &r300->vertex_buffer[vbi]; + stride[i] = vbuf->stride / 4; /* Map the buffer. */ - if (!map[vbi]) { - vbuf = &r300->vertex_buffer[vbi]; + if (!transfer[vbi]) { map[vbi] = (uint32_t*)pipe_buffer_map(&r300->context, vbuf->buffer, PIPE_TRANSFER_READ, &transfer[vbi]); - map[vbi] += vbuf->buffer_offset / 4; - stride[vbi] = vbuf->stride / 4; + map[vbi] += (vbuf->buffer_offset / 4) + stride[i] * start; } + mapelem[i] = map[vbi] + (velem->src_offset / 4); } dwords = 9 + count * vertex_size; r300_prepare_for_rendering(r300, PREP_FIRST_DRAW, NULL, dwords, 0, 0, NULL); - BEGIN_CS(dwords); - OUT_CS_REG(R300_GA_COLOR_CONTROL, + BEGIN_CS_AS_CB(r300, dwords); + OUT_CB_REG(R300_GA_COLOR_CONTROL, r300_provoking_vertex_fixes(r300, mode)); - OUT_CS_REG(R300_VAP_VTX_SIZE, vertex_size); - OUT_CS_REG_SEQ(R300_VAP_VF_MAX_VTX_INDX, 2); - OUT_CS(count - 1); - OUT_CS(0); - OUT_CS_PKT3(R300_PACKET3_3D_DRAW_IMMD_2, count * vertex_size); - OUT_CS(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED | (count << 16) | + OUT_CB_REG(R300_VAP_VTX_SIZE, vertex_size); + OUT_CB_REG_SEQ(R300_VAP_VF_MAX_VTX_INDX, 2); + OUT_CB(count - 1); + OUT_CB(0); + OUT_CB_PKT3(R300_PACKET3_3D_DRAW_IMMD_2, count * vertex_size); + OUT_CB(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED | (count << 16) | r300_translate_primitive(mode)); /* Emit vertices. */ for (v = 0; v < count; v++) { for (i = 0; i < vertex_element_count; i++) { - velem = &r300->velems->velem[i]; - vbi = velem->vertex_buffer_index; - elem_offset = offset[i] + stride[vbi] * (v + start); - - for (dw = 0; dw < size[i]; dw++) { - OUT_CS(map[vbi][elem_offset + dw]); - } + OUT_CB_TABLE(&mapelem[i][stride[i] * v], size[i]); } } - END_CS; + END_CB; /* Unmap buffers. */ for (i = 0; i < vertex_element_count; i++) { vbi = r300->velems->velem[i].vertex_buffer_index; - if (map[vbi]) { + if (transfer[vbi]) { vbuf = &r300->vertex_buffer[vbi]; pipe_buffer_unmap(&r300->context, vbuf->buffer, transfer[vbi]); - map[vbi] = NULL; + transfer[vbi] = NULL; } } } @@ -482,111 +476,6 @@ static void r300_emit_draw_elements(struct r300_context *r300, END_CS; } -static void r300_shorten_ubyte_elts(struct r300_context* r300, - struct pipe_resource** elts, - int index_bias, - unsigned start, - unsigned count) -{ - struct pipe_context* context = &r300->context; - struct pipe_screen* screen = r300->context.screen; - struct pipe_resource* new_elts; - unsigned char *in_map; - unsigned short *out_map; - struct pipe_transfer *src_transfer, *dst_transfer; - unsigned i; - - new_elts = pipe_buffer_create(screen, - PIPE_BIND_INDEX_BUFFER, - 2 * count); - - in_map = pipe_buffer_map(context, *elts, PIPE_TRANSFER_READ, &src_transfer); - out_map = pipe_buffer_map(context, new_elts, PIPE_TRANSFER_WRITE, &dst_transfer); - - in_map += start; - - for (i = 0; i < count; i++) { - *out_map = (unsigned short)(*in_map + index_bias); - in_map++; - out_map++; - } - - pipe_buffer_unmap(context, *elts, src_transfer); - pipe_buffer_unmap(context, new_elts, dst_transfer); - - *elts = new_elts; -} - -static void r300_rebuild_ushort_elts(struct r300_context *r300, - struct pipe_resource **elts, - int index_bias, - unsigned start, unsigned count) -{ - struct pipe_context *context = &r300->context; - struct pipe_transfer *in_transfer = NULL; - struct pipe_transfer *out_transfer = NULL; - struct pipe_resource *new_elts; - unsigned short *in_map; - unsigned short *out_map; - unsigned i; - - new_elts = pipe_buffer_create(context->screen, - PIPE_BIND_INDEX_BUFFER, - 2 * count); - - in_map = pipe_buffer_map(context, *elts, - PIPE_TRANSFER_READ, &in_transfer); - out_map = pipe_buffer_map(context, new_elts, - PIPE_TRANSFER_WRITE, &out_transfer); - - in_map += start; - for (i = 0; i < count; i++) { - *out_map = (unsigned short)(*in_map + index_bias); - in_map++; - out_map++; - } - - pipe_buffer_unmap(context, *elts, in_transfer); - pipe_buffer_unmap(context, new_elts, out_transfer); - - *elts = new_elts; -} - -static void r300_rebuild_uint_elts(struct r300_context *r300, - struct pipe_resource **elts, - int index_bias, - unsigned start, unsigned count) -{ - struct pipe_context *context = &r300->context; - struct pipe_transfer *in_transfer = NULL; - struct pipe_transfer *out_transfer = NULL; - struct pipe_resource *new_elts; - unsigned int *in_map; - unsigned int *out_map; - unsigned i; - - new_elts = pipe_buffer_create(context->screen, - PIPE_BIND_INDEX_BUFFER, - 2 * count); - - in_map = pipe_buffer_map(context, *elts, - PIPE_TRANSFER_READ, &in_transfer); - out_map = pipe_buffer_map(context, new_elts, - PIPE_TRANSFER_WRITE, &out_transfer); - - in_map += start; - for (i = 0; i < count; i++) { - *out_map = (unsigned int)(*in_map + index_bias); - in_map++; - out_map++; - } - - pipe_buffer_unmap(context, *elts, in_transfer); - pipe_buffer_unmap(context, new_elts, out_transfer); - - *elts = new_elts; -} - /* This is the fast-path drawing & emission for HW TCL. */ static void r300_draw_range_elements(struct pipe_context* pipe, struct pipe_resource* indexBuffer, @@ -605,6 +494,7 @@ static void r300_draw_range_elements(struct pipe_context* pipe, r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0); unsigned short_count; int buffer_offset = 0, index_offset = 0; /* for index bias emulation */ + boolean translate = FALSE; if (r300->skip_rendering) { return; @@ -614,33 +504,25 @@ static void r300_draw_range_elements(struct pipe_context* pipe, return; } - if (indexBias && !index_bias_supported(r300)) { - r300_split_index_bias(r300, indexBias, &buffer_offset, &index_offset); + /* Index buffer range checking. */ + if ((start + count) * indexSize > indexBuffer->width0) { + fprintf(stderr, "r300: Invalid index buffer range. Skipping rendering.\n"); + return; } - /* Rebuild the index buffer if needed. */ - switch (indexSize) { - case 1: - r300_shorten_ubyte_elts(r300, &indexBuffer, index_offset, start, count); - indexSize = 2; - start = 0; - break; - - case 2: - if (start % 2 != 0 || index_offset) { - r300_rebuild_ushort_elts(r300, &indexBuffer, index_offset, start, count); - start = 0; - } - break; + /* Set up fallback for incompatible vertex layout if needed. */ + if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) { + r300_begin_vertex_translate(r300); + translate = TRUE; + } - case 4: - if (index_offset) { - r300_rebuild_uint_elts(r300, &indexBuffer, index_offset, start, count); - start = 0; - } - break; + if (indexBias && !index_bias_supported(r300)) { + r300_split_index_bias(r300, indexBias, &buffer_offset, &index_offset); } + r300_translate_index_buffer(r300, &indexBuffer, &indexSize, index_offset, + &start, count); + r300_update_derived_state(r300); r300_upload_index_buffer(r300, &indexBuffer, indexSize, start, count); @@ -676,6 +558,10 @@ static void r300_draw_range_elements(struct pipe_context* pipe, if (indexBuffer != orgIndexBuffer) { pipe_resource_reference( &indexBuffer, NULL ); } + + if (translate) { + r300_end_vertex_translate(r300); + } } /* Simple helpers for context setup. Should probably be moved to util. */ @@ -699,6 +585,7 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode, count > 65536 && r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0); unsigned short_count; + boolean translate = FALSE; if (r300->skip_rendering) { return; @@ -708,6 +595,12 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode, return; } + /* Set up fallback for incompatible vertex layout if needed. */ + if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) { + r300_begin_vertex_translate(r300); + translate = TRUE; + } + r300_update_derived_state(r300); if (immd_is_good_idea(r300, count)) { @@ -737,6 +630,10 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode, } u_upload_flush(r300->upload_vb); } + + if (translate) { + r300_end_vertex_translate(r300); + } } /**************************************************************************** @@ -1016,7 +913,7 @@ static void r300_render_draw_elements(struct vbuf_render* render, unsigned max_index = (r300render->vbo_size - r300render->vbo_offset) / (r300render->r300->vertex_info.size * 4) - 1; unsigned short_count; - struct r300_cs_info cs_info; + unsigned free_dwords; CS_LOCALS(r300); @@ -1029,9 +926,9 @@ static void r300_render_draw_elements(struct vbuf_render* render, NULL, 256, 0, 0, &end_cs_dwords); while (count) { - r300->rws->get_cs_info(r300->rws, &cs_info); + free_dwords = r300->rws->get_cs_free_dwords(r300->rws); - short_count = MIN2(count, (cs_info.free - end_cs_dwords - 6) * 2); + short_count = MIN2(count, (free_dwords - end_cs_dwords - 6) * 2); BEGIN_CS(6 + (short_count+1)/2); OUT_CS_REG(R300_GA_COLOR_CONTROL, @@ -1117,132 +1014,45 @@ struct draw_stage* r300_draw_stage(struct r300_context* r300) } /**************************************************************************** - * Two-sided stencil reference value fallback. It's designed to be as much - * separate from rest of the driver as possible. + * End of SW TCL functions * ***************************************************************************/ -struct r300_stencilref_context { - void (*draw_arrays)(struct pipe_context *pipe, - unsigned mode, unsigned start, unsigned count); - - void (*draw_range_elements)( - struct pipe_context *pipe, struct pipe_resource *indexBuffer, - unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex, - unsigned mode, unsigned start, unsigned count); - - uint32_t rs_cull_mode; - uint32_t zb_stencilrefmask; - ubyte ref_value_front; -}; - -static boolean r300_stencilref_needed(struct r300_context *r300) +static void r300_resource_resolve(struct pipe_context* pipe, + struct pipe_resource* dest, + struct pipe_subresource subdest, + struct pipe_resource* src, + struct pipe_subresource subsrc) { - struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; - - return dsa->two_sided_stencil_ref || - (dsa->two_sided && - r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]); -} - -/* Set drawing for front faces. */ -static void r300_stencilref_begin(struct r300_context *r300) -{ - struct r300_stencilref_context *sr = r300->stencilref_fallback; - struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; - struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; - - /* Save state. */ - sr->rs_cull_mode = rs->cull_mode; - sr->zb_stencilrefmask = dsa->stencil_ref_mask; - sr->ref_value_front = r300->stencil_ref.ref_value[0]; - - /* We *cull* pixels, therefore no need to mask out the bits. */ - rs->cull_mode |= R300_CULL_BACK; - - r300->rs_state.dirty = TRUE; -} - -/* Set drawing for back faces. */ -static void r300_stencilref_switch_side(struct r300_context *r300) -{ - struct r300_stencilref_context *sr = r300->stencilref_fallback; - struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; - struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; - - rs->cull_mode = sr->rs_cull_mode | R300_CULL_FRONT; - dsa->stencil_ref_mask = dsa->stencil_ref_bf; - r300->stencil_ref.ref_value[0] = r300->stencil_ref.ref_value[1]; - - r300->rs_state.dirty = TRUE; - r300->dsa_state.dirty = TRUE; -} - -/* Restore the original state. */ -static void r300_stencilref_end(struct r300_context *r300) -{ - struct r300_stencilref_context *sr = r300->stencilref_fallback; - struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; - struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; - - /* Restore state. */ - rs->cull_mode = sr->rs_cull_mode; - dsa->stencil_ref_mask = sr->zb_stencilrefmask; - r300->stencil_ref.ref_value[0] = sr->ref_value_front; - - r300->rs_state.dirty = TRUE; - r300->dsa_state.dirty = TRUE; -} - -static void r300_stencilref_draw_arrays(struct pipe_context *pipe, unsigned mode, - unsigned start, unsigned count) -{ - struct r300_context *r300 = r300_context(pipe); - struct r300_stencilref_context *sr = r300->stencilref_fallback; - - if (!r300_stencilref_needed(r300)) { - sr->draw_arrays(pipe, mode, start, count); - } else { - r300_stencilref_begin(r300); - sr->draw_arrays(pipe, mode, start, count); - r300_stencilref_switch_side(r300); - sr->draw_arrays(pipe, mode, start, count); - r300_stencilref_end(r300); - } -} - -static void r300_stencilref_draw_range_elements( - struct pipe_context *pipe, struct pipe_resource *indexBuffer, - unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex, - unsigned mode, unsigned start, unsigned count) -{ - struct r300_context *r300 = r300_context(pipe); - struct r300_stencilref_context *sr = r300->stencilref_fallback; - - if (!r300_stencilref_needed(r300)) { - sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias, - minIndex, maxIndex, mode, start, count); - } else { - r300_stencilref_begin(r300); - sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias, - minIndex, maxIndex, mode, start, count); - r300_stencilref_switch_side(r300); - sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias, - minIndex, maxIndex, mode, start, count); - r300_stencilref_end(r300); - } -} - -static void r300_plug_in_stencil_ref_fallback(struct r300_context *r300) -{ - r300->stencilref_fallback = CALLOC_STRUCT(r300_stencilref_context); - - /* Save original draw functions. */ - r300->stencilref_fallback->draw_arrays = r300->context.draw_arrays; - r300->stencilref_fallback->draw_range_elements = r300->context.draw_range_elements; - - /* Override the draw functions. */ - r300->context.draw_arrays = r300_stencilref_draw_arrays; - r300->context.draw_range_elements = r300_stencilref_draw_range_elements; + struct r300_context* r300 = r300_context(pipe); + struct r300_aa_state *aa = (struct r300_aa_state*)r300->aa_state.state; + struct pipe_surface* srcsurf = src->screen->get_tex_surface(src->screen, + src, subsrc.face, subsrc.level, 0, 0); + float color[] = {0, 0, 0, 0}; + + DBG(r300, DBG_DRAW, "r300: Resolving resource...\n"); + + /* Enable AA resolve. */ + aa->dest = r300_surface( + dest->screen->get_tex_surface(dest->screen, dest, subdest.face, + subdest.level, 0, 0)); + + aa->aaresolve_ctl = + R300_RB3D_AARESOLVE_CTL_AARESOLVE_MODE_RESOLVE | + R300_RB3D_AARESOLVE_CTL_AARESOLVE_ALPHA_AVERAGE; + r300->aa_state.size = 12; + r300->aa_state.dirty = TRUE; + + /* Resolve the surface. */ + r300->context.clear_render_target(pipe, + srcsurf, color, 0, 0, src->width0, src->height0); + + /* Disable AA resolve. */ + aa->aaresolve_ctl = 0; + r300->aa_state.size = 4; + r300->aa_state.dirty = TRUE; + + pipe_surface_reference((struct pipe_surface**)&srcsurf, NULL); + pipe_surface_reference((struct pipe_surface**)&aa->dest, NULL); } void r300_init_render_functions(struct r300_context *r300) @@ -1259,7 +1069,9 @@ void r300_init_render_functions(struct r300_context *r300) r300->context.draw_range_elements = r300_swtcl_draw_range_elements; } - /* Plug in two-sided stencil reference value fallback if needed. */ + r300->context.resource_resolve = r300_resource_resolve; + + /* Plug in the two-sided stencil reference value fallback if needed. */ if (!r300->screen->caps.is_r500) r300_plug_in_stencil_ref_fallback(r300); } diff --git a/src/gallium/drivers/r300/r300_render_stencilref.c b/src/gallium/drivers/r300/r300_render_stencilref.c new file mode 100644 index 00000000000..9a6b4e12ff1 --- /dev/null +++ b/src/gallium/drivers/r300/r300_render_stencilref.c @@ -0,0 +1,158 @@ +/* + * Copyright 2010 Marek Olšák <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * The two-sided stencil reference value fallback for r3xx-r4xx chips. + * These chips support two-sided stencil functions but they do not support + * a two-sided reference value. + * + * The functions below split every draw call which uses the two-sided + * reference value into two draw calls -- the first one renders front faces + * and the second renders back faces with the other reference value. + */ + +#include "r300_context.h" +#include "r300_reg.h" + +struct r300_stencilref_context { + void (*draw_arrays)(struct pipe_context *pipe, + unsigned mode, unsigned start, unsigned count); + + void (*draw_range_elements)( + struct pipe_context *pipe, struct pipe_resource *indexBuffer, + unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex, + unsigned mode, unsigned start, unsigned count); + + uint32_t rs_cull_mode; + uint32_t zb_stencilrefmask; + ubyte ref_value_front; +}; + +static boolean r300_stencilref_needed(struct r300_context *r300) +{ + struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; + + return dsa->two_sided_stencil_ref || + (dsa->two_sided && + r300->stencil_ref.ref_value[0] != r300->stencil_ref.ref_value[1]); +} + +/* Set drawing for front faces. */ +static void r300_stencilref_begin(struct r300_context *r300) +{ + struct r300_stencilref_context *sr = r300->stencilref_fallback; + struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; + struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; + + /* Save state. */ + sr->rs_cull_mode = rs->cb_main[rs->cull_mode_index]; + sr->zb_stencilrefmask = dsa->stencil_ref_mask; + sr->ref_value_front = r300->stencil_ref.ref_value[0]; + + /* We *cull* pixels, therefore no need to mask out the bits. */ + rs->cb_main[rs->cull_mode_index] |= R300_CULL_BACK; + + r300->rs_state.dirty = TRUE; +} + +/* Set drawing for back faces. */ +static void r300_stencilref_switch_side(struct r300_context *r300) +{ + struct r300_stencilref_context *sr = r300->stencilref_fallback; + struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; + struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; + + rs->cb_main[rs->cull_mode_index] = sr->rs_cull_mode | R300_CULL_FRONT; + dsa->stencil_ref_mask = dsa->stencil_ref_bf; + r300->stencil_ref.ref_value[0] = r300->stencil_ref.ref_value[1]; + + r300->rs_state.dirty = TRUE; + r300->dsa_state.dirty = TRUE; +} + +/* Restore the original state. */ +static void r300_stencilref_end(struct r300_context *r300) +{ + struct r300_stencilref_context *sr = r300->stencilref_fallback; + struct r300_rs_state *rs = (struct r300_rs_state*)r300->rs_state.state; + struct r300_dsa_state *dsa = (struct r300_dsa_state*)r300->dsa_state.state; + + /* Restore state. */ + rs->cb_main[rs->cull_mode_index] = sr->rs_cull_mode; + dsa->stencil_ref_mask = sr->zb_stencilrefmask; + r300->stencil_ref.ref_value[0] = sr->ref_value_front; + + r300->rs_state.dirty = TRUE; + r300->dsa_state.dirty = TRUE; +} + +static void r300_stencilref_draw_arrays(struct pipe_context *pipe, unsigned mode, + unsigned start, unsigned count) +{ + struct r300_context *r300 = r300_context(pipe); + struct r300_stencilref_context *sr = r300->stencilref_fallback; + + if (!r300_stencilref_needed(r300)) { + sr->draw_arrays(pipe, mode, start, count); + } else { + r300_stencilref_begin(r300); + sr->draw_arrays(pipe, mode, start, count); + r300_stencilref_switch_side(r300); + sr->draw_arrays(pipe, mode, start, count); + r300_stencilref_end(r300); + } +} + +static void r300_stencilref_draw_range_elements( + struct pipe_context *pipe, struct pipe_resource *indexBuffer, + unsigned indexSize, int indexBias, unsigned minIndex, unsigned maxIndex, + unsigned mode, unsigned start, unsigned count) +{ + struct r300_context *r300 = r300_context(pipe); + struct r300_stencilref_context *sr = r300->stencilref_fallback; + + if (!r300_stencilref_needed(r300)) { + sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias, + minIndex, maxIndex, mode, start, count); + } else { + r300_stencilref_begin(r300); + sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias, + minIndex, maxIndex, mode, start, count); + r300_stencilref_switch_side(r300); + sr->draw_range_elements(pipe, indexBuffer, indexSize, indexBias, + minIndex, maxIndex, mode, start, count); + r300_stencilref_end(r300); + } +} + +void r300_plug_in_stencil_ref_fallback(struct r300_context *r300) +{ + r300->stencilref_fallback = CALLOC_STRUCT(r300_stencilref_context); + + /* Save original draw functions. */ + r300->stencilref_fallback->draw_arrays = r300->context.draw_arrays; + r300->stencilref_fallback->draw_range_elements = r300->context.draw_range_elements; + + /* Override the draw functions. */ + r300->context.draw_arrays = r300_stencilref_draw_arrays; + r300->context.draw_range_elements = r300_stencilref_draw_range_elements; +} diff --git a/src/gallium/drivers/r300/r300_render_translate.c b/src/gallium/drivers/r300/r300_render_translate.c new file mode 100644 index 00000000000..0ea11e5bfc2 --- /dev/null +++ b/src/gallium/drivers/r300/r300_render_translate.c @@ -0,0 +1,322 @@ +/* + * Copyright 2010 Marek Olšák <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * The functions below translate vertex and index buffers to the layout + * compatible with the hardware, so that all vertex and index fetches are + * DWORD-aligned and all used vertex and index formats are supported. + * For indices, an optional index offset is added to each index. + */ + +#include "r300_context.h" +#include "translate/translate.h" + +void r300_begin_vertex_translate(struct r300_context *r300) +{ + struct pipe_context *pipe = &r300->context; + struct translate_key key = {0}; + struct translate_element *te; + unsigned tr_elem_index[PIPE_MAX_ATTRIBS] = {0}; + struct translate *tr; + struct r300_vertex_element_state *ve = r300->velems; + boolean vb_translated[PIPE_MAX_ATTRIBS] = {0}; + void *vb_map[PIPE_MAX_ATTRIBS] = {0}, *out_map; + struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = {0}, *out_transfer; + struct pipe_resource *out_buffer; + unsigned i, num_verts; + + /* Initialize the translate key, i.e. the recipe how vertices should be + * translated. */ + for (i = 0; i < ve->count; i++) { + struct pipe_vertex_buffer *vb = + &r300->vertex_buffer[ve->velem[i].vertex_buffer_index]; + enum pipe_format output_format = ve->hw_format[i]; + unsigned output_format_size = ve->hw_format_size[i]; + + /* Check for support. */ + if (ve->velem[i].src_format == ve->hw_format[i] && + (vb->buffer_offset + ve->velem[i].src_offset) % 4 == 0 && + vb->stride % 4 == 0) { + continue; + } + + /* Workaround for translate: output floats instead of halfs. */ + switch (output_format) { + case PIPE_FORMAT_R16_FLOAT: + output_format = PIPE_FORMAT_R32_FLOAT; + output_format_size = 4; + break; + case PIPE_FORMAT_R16G16_FLOAT: + output_format = PIPE_FORMAT_R32G32_FLOAT; + output_format_size = 8; + break; + case PIPE_FORMAT_R16G16B16_FLOAT: + output_format = PIPE_FORMAT_R32G32B32_FLOAT; + output_format_size = 12; + break; + case PIPE_FORMAT_R16G16B16A16_FLOAT: + output_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + output_format_size = 16; + break; + default:; + } + + /* Add this vertex element. */ + te = &key.element[key.nr_elements]; + /*te->type; + te->instance_divisor;*/ + te->input_buffer = ve->velem[i].vertex_buffer_index; + te->input_format = ve->velem[i].src_format; + te->input_offset = vb->buffer_offset + ve->velem[i].src_offset; + te->output_format = output_format; + te->output_offset = key.output_stride; + + key.output_stride += output_format_size; + vb_translated[ve->velem[i].vertex_buffer_index] = TRUE; + tr_elem_index[i] = key.nr_elements; + key.nr_elements++; + } + + /* Get a translate object. */ + tr = translate_cache_find(r300->tran.translate_cache, &key); + + /* Map buffers we want to translate. */ + for (i = 0; i < r300->vertex_buffer_count; i++) { + if (vb_translated[i]) { + struct pipe_vertex_buffer *vb = &r300->vertex_buffer[i]; + + vb_map[i] = pipe_buffer_map(pipe, vb->buffer, + PIPE_TRANSFER_READ, &vb_transfer[i]); + + tr->set_buffer(tr, i, vb_map[i], vb->stride, vb->max_index); + } + } + + /* Create and map the output buffer. */ + num_verts = r300->vertex_buffer_max_index + 1; + + out_buffer = pipe_buffer_create(&r300->screen->screen, + PIPE_BIND_VERTEX_BUFFER, + key.output_stride * num_verts); + + out_map = pipe_buffer_map(pipe, out_buffer, PIPE_TRANSFER_WRITE, + &out_transfer); + + /* Translate. */ + tr->run(tr, 0, num_verts, 0, out_map); + + /* Unmap all buffers. */ + for (i = 0; i < r300->vertex_buffer_count; i++) { + if (vb_translated[i]) { + pipe_buffer_unmap(pipe, r300->vertex_buffer[i].buffer, + vb_transfer[i]); + } + } + + pipe_buffer_unmap(pipe, out_buffer, out_transfer); + + /* Setup the new vertex buffer in the first free slot. */ + for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { + struct pipe_vertex_buffer *vb = &r300->vertex_buffer[i]; + + if (!vb->buffer) { + pipe_resource_reference(&vb->buffer, out_buffer); + vb->buffer_offset = 0; + vb->max_index = num_verts - 1; + vb->stride = key.output_stride; + r300->tran.vb_slot = i; + break; + } + } + + /* Save and replace vertex elements. */ + { + struct pipe_vertex_element new_velems[PIPE_MAX_ATTRIBS]; + + r300->tran.saved_velems = r300->velems; + + for (i = 0; i < ve->count; i++) { + if (vb_translated[ve->velem[i].vertex_buffer_index]) { + te = &key.element[tr_elem_index[i]]; + new_velems[i].instance_divisor = ve->velem[i].instance_divisor; + new_velems[i].src_format = te->output_format; + new_velems[i].src_offset = te->output_offset; + new_velems[i].vertex_buffer_index = r300->tran.vb_slot; + } else { + memcpy(&new_velems[i], &ve->velem[i], + sizeof(struct pipe_vertex_element)); + } + } + + r300->tran.new_velems = + pipe->create_vertex_elements_state(pipe, ve->count, new_velems); + pipe->bind_vertex_elements_state(pipe, r300->tran.new_velems); + } + + pipe_resource_reference(&out_buffer, NULL); +} + +void r300_end_vertex_translate(struct r300_context *r300) +{ + struct pipe_context *pipe = &r300->context; + + /* Restore vertex elements. */ + pipe->bind_vertex_elements_state(pipe, r300->tran.saved_velems); + pipe->delete_vertex_elements_state(pipe, r300->tran.new_velems); + + /* Delete the now-unused VBO. */ + pipe_resource_reference(&r300->vertex_buffer[r300->tran.vb_slot].buffer, + NULL); +} + +static void r300_shorten_ubyte_elts(struct r300_context* r300, + struct pipe_resource** elts, + int index_bias, + unsigned start, + unsigned count) +{ + struct pipe_context* context = &r300->context; + struct pipe_screen* screen = r300->context.screen; + struct pipe_resource* new_elts; + unsigned char *in_map; + unsigned short *out_map; + struct pipe_transfer *src_transfer, *dst_transfer; + unsigned i; + + new_elts = pipe_buffer_create(screen, + PIPE_BIND_INDEX_BUFFER, + 2 * count); + + in_map = pipe_buffer_map(context, *elts, PIPE_TRANSFER_READ, &src_transfer); + out_map = pipe_buffer_map(context, new_elts, PIPE_TRANSFER_WRITE, &dst_transfer); + + in_map += start; + + for (i = 0; i < count; i++) { + *out_map = (unsigned short)(*in_map + index_bias); + in_map++; + out_map++; + } + + pipe_buffer_unmap(context, *elts, src_transfer); + pipe_buffer_unmap(context, new_elts, dst_transfer); + + *elts = new_elts; +} + +static void r300_rebuild_ushort_elts(struct r300_context *r300, + struct pipe_resource **elts, + int index_bias, + unsigned start, unsigned count) +{ + struct pipe_context *context = &r300->context; + struct pipe_transfer *in_transfer = NULL; + struct pipe_transfer *out_transfer = NULL; + struct pipe_resource *new_elts; + unsigned short *in_map; + unsigned short *out_map; + unsigned i; + + new_elts = pipe_buffer_create(context->screen, + PIPE_BIND_INDEX_BUFFER, + 2 * count); + + in_map = pipe_buffer_map(context, *elts, + PIPE_TRANSFER_READ, &in_transfer); + out_map = pipe_buffer_map(context, new_elts, + PIPE_TRANSFER_WRITE, &out_transfer); + + in_map += start; + for (i = 0; i < count; i++) { + *out_map = (unsigned short)(*in_map + index_bias); + in_map++; + out_map++; + } + + pipe_buffer_unmap(context, *elts, in_transfer); + pipe_buffer_unmap(context, new_elts, out_transfer); + + *elts = new_elts; +} + +static void r300_rebuild_uint_elts(struct r300_context *r300, + struct pipe_resource **elts, + int index_bias, + unsigned start, unsigned count) +{ + struct pipe_context *context = &r300->context; + struct pipe_transfer *in_transfer = NULL; + struct pipe_transfer *out_transfer = NULL; + struct pipe_resource *new_elts; + unsigned int *in_map; + unsigned int *out_map; + unsigned i; + + new_elts = pipe_buffer_create(context->screen, + PIPE_BIND_INDEX_BUFFER, + 2 * count); + + in_map = pipe_buffer_map(context, *elts, + PIPE_TRANSFER_READ, &in_transfer); + out_map = pipe_buffer_map(context, new_elts, + PIPE_TRANSFER_WRITE, &out_transfer); + + in_map += start; + for (i = 0; i < count; i++) { + *out_map = (unsigned int)(*in_map + index_bias); + in_map++; + out_map++; + } + + pipe_buffer_unmap(context, *elts, in_transfer); + pipe_buffer_unmap(context, new_elts, out_transfer); + + *elts = new_elts; +} + +void r300_translate_index_buffer(struct r300_context *r300, + struct pipe_resource **index_buffer, + unsigned *index_size, unsigned index_offset, + unsigned *start, unsigned count) +{ + switch (*index_size) { + case 1: + r300_shorten_ubyte_elts(r300, index_buffer, index_offset, *start, count); + *index_size = 2; + *start = 0; + break; + + case 2: + if (*start % 2 != 0 || index_offset) { + r300_rebuild_ushort_elts(r300, index_buffer, index_offset, *start, count); + *start = 0; + } + break; + + case 4: + if (index_offset) { + r300_rebuild_uint_elts(r300, index_buffer, index_offset, *start, count); + *start = 0; + } + break; + } +} diff --git a/src/gallium/drivers/r300/r300_screen.c b/src/gallium/drivers/r300/r300_screen.c index fd522b84e1a..5bba55906c3 100644 --- a/src/gallium/drivers/r300/r300_screen.c +++ b/src/gallium/drivers/r300/r300_screen.c @@ -270,15 +270,24 @@ static boolean r300_is_format_supported(struct pipe_screen* screen, format == PIPE_FORMAT_R16G16B16_FLOAT || format == PIPE_FORMAT_R16G16B16A16_FLOAT; - if (target >= PIPE_MAX_TEXTURE_TYPES) { - fprintf(stderr, "r300: Implementation error: Received bogus texture " - "target %d in %s\n", target, __FUNCTION__); - return FALSE; + switch (sample_count) { + case 0: + case 1: + break; + case 2: + case 3: + case 4: + case 6: + if (usage != PIPE_BIND_RENDER_TARGET || + !util_format_is_rgba8_variant( + util_format_description(format))) { + return FALSE; + } + break; + default: + return FALSE; } - if (sample_count > 1) - return FALSE; - /* Check sampler format support. */ if ((usage & PIPE_BIND_SAMPLER_VIEW) && /* Z24 cannot be sampled from on non-r5xx. */ @@ -320,6 +329,12 @@ static boolean r300_is_format_supported(struct pipe_screen* screen, retval |= PIPE_BIND_VERTEX_BUFFER; } + /* Transfers are always supported. */ + if (usage & PIPE_BIND_TRANSFER_READ) + retval |= PIPE_BIND_TRANSFER_READ; + if (usage & PIPE_BIND_TRANSFER_WRITE) + retval |= PIPE_BIND_TRANSFER_WRITE; + return retval == usage; } diff --git a/src/gallium/drivers/r300/r300_screen.h b/src/gallium/drivers/r300/r300_screen.h index 29492024fe3..29cd5dbe267 100644 --- a/src/gallium/drivers/r300/r300_screen.h +++ b/src/gallium/drivers/r300/r300_screen.h @@ -65,7 +65,7 @@ static INLINE struct r300_screen* r300_screen(struct pipe_screen* screen) { /* Logging. */ #define DBG_FP (1 << 1) #define DBG_VP (1 << 2) -#define DBG_CS (1 << 3) +/* The bit (1 << 3) is unused. */ #define DBG_DRAW (1 << 4) #define DBG_TEX (1 << 5) #define DBG_TEXALLOC (1 << 6) @@ -76,6 +76,7 @@ static INLINE struct r300_screen* r300_screen(struct pipe_screen* screen) { #define DBG_ANISOHQ (1 << 16) #define DBG_NO_TILING (1 << 17) #define DBG_NO_IMMD (1 << 18) +#define DBG_FAKE_OCC (1 << 19) /* Statistics. */ #define DBG_STATS (1 << 24) /*@}*/ diff --git a/src/gallium/drivers/r300/r300_screen_buffer.c b/src/gallium/drivers/r300/r300_screen_buffer.c index 44179f19ed4..7959e6a2f9e 100644 --- a/src/gallium/drivers/r300/r300_screen_buffer.c +++ b/src/gallium/drivers/r300/r300_screen_buffer.c @@ -93,25 +93,28 @@ int r300_upload_user_buffers(struct r300_context *r300) enum pipe_error ret = PIPE_OK; int i, nr; - nr = r300->vertex_buffer_count; + nr = r300->velems->count; for (i = 0; i < nr; i++) { - if (r300_buffer_is_user_buffer(r300->vertex_buffer[i].buffer)) { - struct pipe_resource *upload_buffer = NULL; - unsigned offset = 0; /*r300->vertex_buffer[i].buffer_offset * 4;*/ - unsigned size = r300->vertex_buffer[i].buffer->width0; - unsigned upload_offset; - ret = u_upload_buffer(r300->upload_vb, - offset, size, - r300->vertex_buffer[i].buffer, - &upload_offset, &upload_buffer); - if (ret) - return ret; - - pipe_resource_reference(&r300->vertex_buffer[i].buffer, NULL); - r300->vertex_buffer[i].buffer = upload_buffer; - r300->vertex_buffer[i].buffer_offset = upload_offset; - } + struct pipe_vertex_buffer *vb = + &r300->vertex_buffer[r300->velems->velem[i].vertex_buffer_index]; + + if (r300_buffer_is_user_buffer(vb->buffer)) { + struct pipe_resource *upload_buffer = NULL; + unsigned offset = 0; /*vb->buffer_offset * 4;*/ + unsigned size = vb->buffer->width0; + unsigned upload_offset; + ret = u_upload_buffer(r300->upload_vb, + offset, size, + vb->buffer, + &upload_offset, &upload_buffer); + if (ret) + return ret; + + pipe_resource_reference(&vb->buffer, NULL); + vb->buffer = upload_buffer; + vb->buffer_offset = upload_offset; + } } return ret; } @@ -261,10 +264,6 @@ struct pipe_resource *r300_buffer_create(struct pipe_screen *screen, rbuf->b.vtbl = &r300_buffer_vtbl; pipe_reference_init(&rbuf->b.b.reference, 1); rbuf->b.b.screen = screen; - - if (rbuf->b.b.bind & R300_BIND_OQBO) - alignment = 4096; - rbuf->domain = R300_DOMAIN_GTT; rbuf->buf = r300screen->rws->buffer_create(r300screen->rws, diff --git a/src/gallium/drivers/r300/r300_screen_buffer.h b/src/gallium/drivers/r300/r300_screen_buffer.h index 87b42b94122..ff355858704 100644 --- a/src/gallium/drivers/r300/r300_screen_buffer.h +++ b/src/gallium/drivers/r300/r300_screen_buffer.h @@ -116,25 +116,4 @@ static INLINE boolean r300_add_texture(struct r300_winsys_screen *rws, return rws->add_buffer(rws, tex->buffer, rd, wr); } -static INLINE void r300_buffer_write_reloc(struct r300_winsys_screen *rws, - struct r300_buffer *buf, - enum r300_buffer_domain rd, - enum r300_buffer_domain wd, - uint32_t flags) -{ - if (!buf->buf) - return; - - rws->write_cs_reloc(rws, buf->buf, rd, wd, flags); -} - -static INLINE void r300_texture_write_reloc(struct r300_winsys_screen *rws, - struct r300_texture *texture, - enum r300_buffer_domain rd, - enum r300_buffer_domain wd, - uint32_t flags) -{ - rws->write_cs_reloc(rws, texture->buffer, rd, wd, flags); -} - #endif diff --git a/src/gallium/drivers/r300/r300_state.c b/src/gallium/drivers/r300/r300_state.c index cfec8ac2b7e..15de533778f 100644 --- a/src/gallium/drivers/r300/r300_state.c +++ b/src/gallium/drivers/r300/r300_state.c @@ -31,12 +31,12 @@ #include "pipe/p_config.h" +#include "r300_cb.h" #include "r300_context.h" #include "r300_emit.h" #include "r300_reg.h" #include "r300_screen.h" #include "r300_screen_buffer.h" -#include "r300_state.h" #include "r300_state_inlines.h" #include "r300_fs.h" #include "r300_texture.h" @@ -183,6 +183,12 @@ static void* r300_create_blend_state(struct pipe_context* pipe, { struct r300_screen* r300screen = r300_screen(pipe->screen); struct r300_blend_state* blend = CALLOC_STRUCT(r300_blend_state); + uint32_t blend_control = 0; /* R300_RB3D_CBLEND: 0x4e04 */ + uint32_t alpha_blend_control = 0; /* R300_RB3D_ABLEND: 0x4e08 */ + uint32_t color_channel_mask = 0; /* R300_RB3D_COLOR_CHANNEL_MASK: 0x4e0c */ + uint32_t rop = 0; /* R300_RB3D_ROPCNTL: 0x4e18 */ + uint32_t dither = 0; /* R300_RB3D_DITHER_CTL: 0x4e50 */ + CB_LOCALS; if (state->rt[0].blend_enable) { @@ -196,7 +202,7 @@ static void* r300_create_blend_state(struct pipe_context* pipe, /* despite the name, ALPHA_BLEND_ENABLE has nothing to do with alpha, * this is just the crappy D3D naming */ - blend->blend_control = R300_ALPHA_BLEND_ENABLE | + blend_control = R300_ALPHA_BLEND_ENABLE | r300_translate_blend_function(eqRGB) | ( r300_translate_blend_factor(srcRGB) << R300_SRC_BLEND_SHIFT) | ( r300_translate_blend_factor(dstRGB) << R300_DST_BLEND_SHIFT); @@ -220,7 +226,7 @@ static void* r300_create_blend_state(struct pipe_context* pipe, srcA == PIPE_BLENDFACTOR_INV_DST_ALPHA || srcRGB == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE) { /* Enable reading from the colorbuffer. */ - blend->blend_control |= R300_READ_ENABLE; + blend_control |= R300_READ_ENABLE; if (r300screen->caps.is_r500) { /* Optimization: Depending on incoming pixels, we can @@ -233,7 +239,7 @@ static void* r300_create_blend_state(struct pipe_context* pipe, (dstA == PIPE_BLENDFACTOR_SRC_COLOR || dstA == PIPE_BLENDFACTOR_SRC_ALPHA || dstA == PIPE_BLENDFACTOR_ZERO)) { - blend->blend_control |= R500_SRC_ALPHA_0_NO_READ; + blend_control |= R500_SRC_ALPHA_0_NO_READ; } /* Disable reading if SRC_ALPHA == 1. */ @@ -242,7 +248,7 @@ static void* r300_create_blend_state(struct pipe_context* pipe, (dstA == PIPE_BLENDFACTOR_INV_SRC_COLOR || dstA == PIPE_BLENDFACTOR_INV_SRC_ALPHA || dstA == PIPE_BLENDFACTOR_ZERO)) { - blend->blend_control |= R500_SRC_ALPHA_1_NO_READ; + blend_control |= R500_SRC_ALPHA_1_NO_READ; } } } @@ -272,31 +278,31 @@ static void* r300_create_blend_state(struct pipe_context* pipe, * pixels. */ if (blend_discard_if_src_alpha_0(srcRGB, srcA, dstRGB, dstA)) { - blend->blend_control |= R300_DISCARD_SRC_PIXELS_SRC_ALPHA_0; + blend_control |= R300_DISCARD_SRC_PIXELS_SRC_ALPHA_0; } else if (blend_discard_if_src_alpha_1(srcRGB, srcA, dstRGB, dstA)) { - blend->blend_control |= R300_DISCARD_SRC_PIXELS_SRC_ALPHA_1; + blend_control |= R300_DISCARD_SRC_PIXELS_SRC_ALPHA_1; } else if (blend_discard_if_src_color_0(srcRGB, srcA, dstRGB, dstA)) { - blend->blend_control |= R300_DISCARD_SRC_PIXELS_SRC_COLOR_0; + blend_control |= R300_DISCARD_SRC_PIXELS_SRC_COLOR_0; } else if (blend_discard_if_src_color_1(srcRGB, srcA, dstRGB, dstA)) { - blend->blend_control |= R300_DISCARD_SRC_PIXELS_SRC_COLOR_1; + blend_control |= R300_DISCARD_SRC_PIXELS_SRC_COLOR_1; } else if (blend_discard_if_src_alpha_color_0(srcRGB, srcA, dstRGB, dstA)) { - blend->blend_control |= + blend_control |= R300_DISCARD_SRC_PIXELS_SRC_ALPHA_COLOR_0; } else if (blend_discard_if_src_alpha_color_1(srcRGB, srcA, dstRGB, dstA)) { - blend->blend_control |= + blend_control |= R300_DISCARD_SRC_PIXELS_SRC_ALPHA_COLOR_1; } } /* separate alpha */ if (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB) { - blend->blend_control |= R300_SEPARATE_ALPHA_ENABLE; - blend->alpha_blend_control = + blend_control |= R300_SEPARATE_ALPHA_ENABLE; + alpha_blend_control = r300_translate_blend_function(eqA) | (r300_translate_blend_factor(srcA) << R300_SRC_BLEND_SHIFT) | (r300_translate_blend_factor(dstA) << R300_DST_BLEND_SHIFT); @@ -305,21 +311,21 @@ static void* r300_create_blend_state(struct pipe_context* pipe, /* PIPE_LOGICOP_* don't need to be translated, fortunately. */ if (state->logicop_enable) { - blend->rop = R300_RB3D_ROPCNTL_ROP_ENABLE | + rop = R300_RB3D_ROPCNTL_ROP_ENABLE | (state->logicop_func) << R300_RB3D_ROPCNTL_ROP_SHIFT; } /* Color channel masks for all MRTs. */ - blend->color_channel_mask = bgra_cmask(state->rt[0].colormask); + color_channel_mask = bgra_cmask(state->rt[0].colormask); if (r300screen->caps.is_r500 && state->independent_blend_enable) { if (state->rt[1].blend_enable) { - blend->color_channel_mask |= bgra_cmask(state->rt[1].colormask) << 4; + color_channel_mask |= bgra_cmask(state->rt[1].colormask) << 4; } if (state->rt[2].blend_enable) { - blend->color_channel_mask |= bgra_cmask(state->rt[2].colormask) << 8; + color_channel_mask |= bgra_cmask(state->rt[2].colormask) << 8; } if (state->rt[3].blend_enable) { - blend->color_channel_mask |= bgra_cmask(state->rt[3].colormask) << 12; + color_channel_mask |= bgra_cmask(state->rt[3].colormask) << 12; } } @@ -330,11 +336,31 @@ static void* r300_create_blend_state(struct pipe_context* pipe, * This could be revisited if we ever get quality or conformance hints. * if (state->dither) { - blend->dither = R300_RB3D_DITHER_CTL_DITHER_MODE_LUT | + dither = R300_RB3D_DITHER_CTL_DITHER_MODE_LUT | R300_RB3D_DITHER_CTL_ALPHA_DITHER_MODE_LUT; } */ + /* Build a command buffer. */ + BEGIN_CB(blend->cb, 8); + OUT_CB_REG(R300_RB3D_ROPCNTL, rop); + OUT_CB_REG_SEQ(R300_RB3D_CBLEND, 3); + OUT_CB(blend_control); + OUT_CB(alpha_blend_control); + OUT_CB(color_channel_mask); + OUT_CB_REG(R300_RB3D_DITHER_CTL, dither); + END_CB; + + /* The same as above, but with no colorbuffer reads and writes. */ + BEGIN_CB(blend->cb_no_readwrite, 8); + OUT_CB_REG(R300_RB3D_ROPCNTL, rop); + OUT_CB_REG_SEQ(R300_RB3D_CBLEND, 3); + OUT_CB(0); + OUT_CB(0); + OUT_CB(0); + OUT_CB_REG(R300_RB3D_DITHER_CTL, dither); + END_CB; + return (void*)blend; } @@ -368,20 +394,26 @@ static void r300_set_blend_color(struct pipe_context* pipe, struct r300_context* r300 = r300_context(pipe); struct r300_blend_color_state* state = (struct r300_blend_color_state*)r300->blend_color_state.state; - union util_color uc; + CB_LOCALS; - util_pack_color(color->color, PIPE_FORMAT_B8G8R8A8_UNORM, &uc); - state->blend_color = uc.ui; + if (r300->screen->caps.is_r500) { + /* XXX if FP16 blending is enabled, we should use the FP16 format */ + BEGIN_CB(state->cb, 3); + OUT_CB_REG_SEQ(R500_RB3D_CONSTANT_COLOR_AR, 2); + OUT_CB(float_to_fixed10(color->color[0]) | + (float_to_fixed10(color->color[3]) << 16)); + OUT_CB(float_to_fixed10(color->color[2]) | + (float_to_fixed10(color->color[1]) << 16)); + END_CB; + } else { + union util_color uc; + util_pack_color(color->color, PIPE_FORMAT_B8G8R8A8_UNORM, &uc); - /* XXX if FP16 blending is enabled, we should use the FP16 format */ - state->blend_color_red_alpha = - float_to_fixed10(color->color[0]) | - (float_to_fixed10(color->color[3]) << 16); - state->blend_color_green_blue = - float_to_fixed10(color->color[2]) | - (float_to_fixed10(color->color[1]) << 16); + BEGIN_CB(state->cb, 2); + OUT_CB_REG(R300_RB3D_BLEND_COLOR, uc.ui); + END_CB; + } - r300->blend_color_state.size = r300->screen->caps.is_r500 ? 3 : 2; r300->blend_color_state.dirty = TRUE; } @@ -389,18 +421,27 @@ static void r300_set_clip_state(struct pipe_context* pipe, const struct pipe_clip_state* state) { struct r300_context* r300 = r300_context(pipe); + struct r300_clip_state *clip = + (struct r300_clip_state*)r300->clip_state.state; + CB_LOCALS; - r300->clip = *state; + clip->clip = *state; if (r300->screen->caps.has_tcl) { - memcpy(r300->clip_state.state, state, sizeof(struct pipe_clip_state)); - r300->clip_state.size = 29; + BEGIN_CB(clip->cb, 29); + OUT_CB_REG(R300_VAP_PVS_VECTOR_INDX_REG, + (r300->screen->caps.is_r500 ? + R500_PVS_UCP_START : R300_PVS_UCP_START)); + OUT_CB_ONE_REG(R300_VAP_PVS_UPLOAD_DATA, 6 * 4); + OUT_CB_TABLE(state->ucp, 6 * 4); + OUT_CB_REG(R300_VAP_CLIP_CNTL, ((1 << state->nr) - 1) | + R300_PS_UCP_MODE_CLIP_AS_TRIFAN); + END_CB; r300->clip_state.dirty = TRUE; } else { draw_flush(r300->draw); draw_set_clip_state(r300->draw, state); - r300->clip_state.size = 2; } } @@ -422,6 +463,9 @@ static void* { struct r300_capabilities *caps = &r300_screen(pipe->screen)->caps; struct r300_dsa_state* dsa = CALLOC_STRUCT(r300_dsa_state); + CB_LOCALS; + + dsa->dsa = *state; /* Depth test setup. */ if (state->depth.enabled) { @@ -494,9 +538,43 @@ static void* dsa->alpha_function |= R500_FG_ALPHA_FUNC_8BIT; } + BEGIN_CB(&dsa->cb_begin, 8); + OUT_CB_REG(R300_FG_ALPHA_FUNC, dsa->alpha_function); + OUT_CB_REG_SEQ(R300_ZB_CNTL, 3); + OUT_CB(dsa->z_buffer_control); + OUT_CB(dsa->z_stencil_control); + OUT_CB(dsa->stencil_ref_mask); + OUT_CB_REG(R500_ZB_STENCILREFMASK_BF, dsa->stencil_ref_bf); + END_CB; + + BEGIN_CB(dsa->cb_no_readwrite, 8); + OUT_CB_REG(R300_FG_ALPHA_FUNC, dsa->alpha_function); + OUT_CB_REG_SEQ(R300_ZB_CNTL, 3); + OUT_CB(0); + OUT_CB(0); + OUT_CB(0); + OUT_CB_REG(R500_ZB_STENCILREFMASK_BF, 0); + END_CB; + return (void*)dsa; } +static void r300_dsa_inject_stencilref(struct r300_context *r300) +{ + struct r300_dsa_state *dsa = + (struct r300_dsa_state*)r300->dsa_state.state; + + if (!dsa) + return; + + dsa->stencil_ref_mask = + (dsa->stencil_ref_mask & ~R300_STENCILREF_MASK) | + r300->stencil_ref.ref_value[0]; + dsa->stencil_ref_bf = + (dsa->stencil_ref_bf & ~R300_STENCILREF_MASK) | + r300->stencil_ref.ref_value[1]; +} + /* Bind DSA state. */ static void r300_bind_dsa_state(struct pipe_context* pipe, void* state) @@ -508,6 +586,8 @@ static void r300_bind_dsa_state(struct pipe_context* pipe, } UPDATE_STATE(state, r300->dsa_state); + + r300_dsa_inject_stencilref(r300); } /* Free DSA state. */ @@ -523,6 +603,8 @@ static void r300_set_stencil_ref(struct pipe_context* pipe, struct r300_context* r300 = r300_context(pipe); r300->stencil_ref = *sr; + + r300_dsa_inject_stencilref(r300); r300->dsa_state.dirty = TRUE; } @@ -577,21 +659,34 @@ static void r300_print_fb_surf_info(struct pipe_surface *surf, unsigned index, tex->last_level, util_format_short_name(tex->format)); } +static void copy_framebuffer_state(struct pipe_framebuffer_state *dst, + const struct pipe_framebuffer_state *src) +{ + unsigned i; + + for (i = 0; i < src->nr_cbufs; i++) { + pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]); + } + for (; i < dst->nr_cbufs; i++) { + pipe_surface_reference(&dst->cbufs[i], NULL); + } + pipe_surface_reference(&dst->zsbuf, src->zsbuf); + + dst->nr_cbufs = src->nr_cbufs; + dst->width = src->width; + dst->height = src->height; +} + static void r300_set_framebuffer_state(struct pipe_context* pipe, const struct pipe_framebuffer_state* state) { struct r300_context* r300 = r300_context(pipe); + struct r300_aa_state *aa = (struct r300_aa_state*)r300->aa_state.state; struct pipe_framebuffer_state *old_state = r300->fb_state.state; unsigned max_width, max_height, i; uint32_t zbuffer_bpp = 0; - if (state->nr_cbufs > 4) { - fprintf(stderr, "r300: Implementation error: Too many MRTs in %s, " - "refusing to bind framebuffer state!\n", __FUNCTION__); - return; - } - if (r300->screen->caps.is_r500) { max_width = max_height = 4096; } else if (r300->screen->caps.is_r400) { @@ -610,7 +705,11 @@ static void draw_flush(r300->draw); } + r300->gpu_flush.dirty = TRUE; + r300->aa_state.dirty = TRUE; r300->fb_state.dirty = TRUE; + r300->hyperz_state.dirty = TRUE; + r300->fb_state_pipelined.dirty = TRUE; /* If nr_cbufs is changed from zero to non-zero or vice versa... */ if (!!old_state->nr_cbufs != !!state->nr_cbufs) { @@ -624,10 +723,12 @@ static void /* The tiling flags are dependent on the surface miplevel, unfortunately. */ r300_fb_set_tiling_flags(r300, r300->fb_state.state, state); - memcpy(r300->fb_state.state, state, sizeof(struct pipe_framebuffer_state)); + copy_framebuffer_state(r300->fb_state.state, state); - r300->fb_state.size = (10 * state->nr_cbufs) + (2 * (4 - state->nr_cbufs)) + - (state->zsbuf ? 10 : 0) + 9; + r300->fb_state.size = + 2 + + (8 * state->nr_cbufs) + + (state->zsbuf ? (r300->screen->caps.has_hiz ? 18 : 14) : 0); /* Polygon offset depends on the zbuffer bit depth. */ if (state->zsbuf && r300->polygon_offset_enabled) { @@ -646,6 +747,30 @@ static void } } + /* Set up AA config. */ + if (r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0)) { + if (state->nr_cbufs && state->cbufs[0]->texture->nr_samples > 1) { + aa->aa_config = R300_GB_AA_CONFIG_AA_ENABLE; + + switch (state->cbufs[0]->texture->nr_samples) { + case 2: + aa->aa_config |= R300_GB_AA_CONFIG_NUM_AA_SUBSAMPLES_2; + break; + case 3: + aa->aa_config |= R300_GB_AA_CONFIG_NUM_AA_SUBSAMPLES_3; + break; + case 4: + aa->aa_config |= R300_GB_AA_CONFIG_NUM_AA_SUBSAMPLES_4; + break; + case 6: + aa->aa_config |= R300_GB_AA_CONFIG_NUM_AA_SUBSAMPLES_6; + break; + } + } else { + aa->aa_config = 0; + } + } + if (DBG_ON(r300, DBG_FB)) { fprintf(stderr, "r300: set_framebuffer_state:\n"); for (i = 0; i < state->nr_cbufs; i++) { @@ -679,13 +804,12 @@ void r300_mark_fs_code_dirty(struct r300_context *r300) r300->fs.dirty = TRUE; r300->fs_rc_constant_state.dirty = TRUE; r300->fs_constants.dirty = TRUE; + r300->fs.size = fs->shader->cb_code_size; if (r300->screen->caps.is_r500) { - r300->fs.size = r500_get_fs_atom_size(r300); r300->fs_rc_constant_state.size = fs->shader->rc_state_count * 7; r300->fs_constants.size = fs->shader->externals_count * 4 + 3; } else { - r300->fs.size = r300_get_fs_atom_size(r300); r300->fs_rc_constant_state.size = fs->shader->rc_state_count * 5; r300->fs_constants.size = fs->shader->externals_count * 4 + 1; } @@ -719,6 +843,7 @@ static void r300_delete_fs_state(struct pipe_context* pipe, void* shader) tmp = ptr; ptr = ptr->next; rc_constants_destroy(&tmp->code.constants); + FREE(tmp->cb_code); FREE(tmp); } FREE((void*)fs->state.tokens); @@ -744,6 +869,27 @@ static void* r300_create_rs_state(struct pipe_context* pipe, struct r300_rs_state* rs = CALLOC_STRUCT(r300_rs_state); int i; float psiz; + uint32_t vap_control_status; /* R300_VAP_CNTL_STATUS: 0x2140 */ + uint32_t point_size; /* R300_GA_POINT_SIZE: 0x421c */ + uint32_t point_minmax; /* R300_GA_POINT_MINMAX: 0x4230 */ + uint32_t line_control; /* R300_GA_LINE_CNTL: 0x4234 */ + uint32_t polygon_offset_enable; /* R300_SU_POLY_OFFSET_ENABLE: 0x42b4 */ + uint32_t cull_mode; /* R300_SU_CULL_MODE: 0x42b8 */ + uint32_t line_stipple_config; /* R300_GA_LINE_STIPPLE_CONFIG: 0x4328 */ + uint32_t line_stipple_value; /* R300_GA_LINE_STIPPLE_VALUE: 0x4260 */ + uint32_t polygon_mode; /* R300_GA_POLY_MODE: 0x4288 */ + uint32_t clip_rule; /* R300_SC_CLIP_RULE: 0x43D0 */ + + /* Specifies top of Raster pipe specific enable controls, + * i.e. texture coordinates stuffing for points, lines, triangles */ + uint32_t stuffing_enable; /* R300_GB_ENABLE: 0x4008 */ + + /* Point sprites texture coordinates, 0: lower left, 1: upper right */ + float point_texcoord_left; /* R300_GA_POINT_S0: 0x4200 */ + float point_texcoord_bottom; /* R300_GA_POINT_T0: 0x4204 */ + float point_texcoord_right; /* R300_GA_POINT_S1: 0x4208 */ + float point_texcoord_top; /* R300_GA_POINT_T1: 0x420c */ + CB_LOCALS; /* Copy rasterizer state. */ rs->rs = *state; @@ -753,18 +899,18 @@ static void* r300_create_rs_state(struct pipe_context* pipe, rs->rs_draw.sprite_coord_enable = 0; /* We can do this in HW. */ #ifdef PIPE_ARCH_LITTLE_ENDIAN - rs->vap_control_status = R300_VC_NO_SWAP; + vap_control_status = R300_VC_NO_SWAP; #else - rs->vap_control_status = R300_VC_32BIT_SWAP; + vap_control_status = R300_VC_32BIT_SWAP; #endif /* If no TCL engine is present, turn off the HW TCL. */ if (!r300_screen(pipe->screen)->caps.has_tcl) { - rs->vap_control_status |= R300_VAP_TCL_BYPASS; + vap_control_status |= R300_VAP_TCL_BYPASS; } /* Point size width and height. */ - rs->point_size = + point_size = pack_float_16_6x(state->point_size) | (pack_float_16_6x(state->point_size) << R300_POINTSIZE_X_SHIFT); @@ -774,68 +920,67 @@ static void* r300_create_rs_state(struct pipe_context* pipe, * Clamp to [0, max FB size] */ psiz = pipe->screen->get_paramf(pipe->screen, PIPE_CAP_MAX_POINT_WIDTH); - rs->point_minmax = + point_minmax = pack_float_16_6x(psiz) << R300_GA_POINT_MINMAX_MAX_SHIFT; } else { /* We cannot disable the point-size vertex output, * so clamp it. */ psiz = state->point_size; - rs->point_minmax = + point_minmax = (pack_float_16_6x(psiz) << R300_GA_POINT_MINMAX_MIN_SHIFT) | (pack_float_16_6x(psiz) << R300_GA_POINT_MINMAX_MAX_SHIFT); } /* Line control. */ - rs->line_control = pack_float_16_6x(state->line_width) | + line_control = pack_float_16_6x(state->line_width) | R300_GA_LINE_CNTL_END_TYPE_COMP; /* Enable polygon mode */ + polygon_mode = 0; if (state->fill_front != PIPE_POLYGON_MODE_FILL || state->fill_back != PIPE_POLYGON_MODE_FILL) { - rs->polygon_mode = R300_GA_POLY_MODE_DUAL; + polygon_mode = R300_GA_POLY_MODE_DUAL; } /* Front face */ if (state->front_ccw) - rs->cull_mode = R300_FRONT_FACE_CCW; + cull_mode = R300_FRONT_FACE_CCW; else - rs->cull_mode = R300_FRONT_FACE_CW; + cull_mode = R300_FRONT_FACE_CW; /* Polygon offset */ + polygon_offset_enable = 0; if (util_get_offset(state, state->fill_front)) { - rs->polygon_offset_enable |= R300_FRONT_ENABLE; + polygon_offset_enable |= R300_FRONT_ENABLE; } if (util_get_offset(state, state->fill_back)) { - rs->polygon_offset_enable |= R300_BACK_ENABLE; + polygon_offset_enable |= R300_BACK_ENABLE; } + rs->polygon_offset_enable = polygon_offset_enable != 0; + /* Polygon mode */ - if (rs->polygon_mode) { - rs->polygon_mode |= + if (polygon_mode) { + polygon_mode |= r300_translate_polygon_mode_front(state->fill_front); - rs->polygon_mode |= + polygon_mode |= r300_translate_polygon_mode_back(state->fill_back); } if (state->cull_face & PIPE_FACE_FRONT) { - rs->cull_mode |= R300_CULL_FRONT; + cull_mode |= R300_CULL_FRONT; } if (state->cull_face & PIPE_FACE_BACK) { - rs->cull_mode |= R300_CULL_BACK; - } - - if (rs->polygon_offset_enable) { - rs->depth_offset = state->offset_units; - rs->depth_scale = state->offset_scale; + cull_mode |= R300_CULL_BACK; } if (state->line_stipple_enable) { - rs->line_stipple_config = + line_stipple_config = R300_GA_LINE_STIPPLE_CONFIG_LINE_RESET_LINE | (fui((float)state->line_stipple_factor) & R300_GA_LINE_STIPPLE_CONFIG_STIPPLE_SCALE_MASK); /* XXX this might need to be scaled up */ - rs->line_stipple_value = state->line_stipple_pattern; + line_stipple_value = state->line_stipple_pattern; } if (state->flatshade) { @@ -844,32 +989,80 @@ static void* r300_create_rs_state(struct pipe_context* pipe, rs->color_control = R300_SHADE_MODEL_SMOOTH; } - rs->clip_rule = state->scissor ? 0xAAAA : 0xFFFF; + clip_rule = state->scissor ? 0xAAAA : 0xFFFF; /* Point sprites */ + stuffing_enable = 0; if (state->sprite_coord_enable) { - rs->stuffing_enable = R300_GB_POINT_STUFF_ENABLE; + stuffing_enable = R300_GB_POINT_STUFF_ENABLE; for (i = 0; i < 8; i++) { if (state->sprite_coord_enable & (1 << i)) - rs->stuffing_enable |= + stuffing_enable |= R300_GB_TEX_STR << (R300_GB_TEX0_SOURCE_SHIFT + (i*2)); } - rs->point_texcoord_left = 0.0f; - rs->point_texcoord_right = 1.0f; + point_texcoord_left = 0.0f; + point_texcoord_right = 1.0f; switch (state->sprite_coord_mode) { case PIPE_SPRITE_COORD_UPPER_LEFT: - rs->point_texcoord_top = 0.0f; - rs->point_texcoord_bottom = 1.0f; + point_texcoord_top = 0.0f; + point_texcoord_bottom = 1.0f; break; case PIPE_SPRITE_COORD_LOWER_LEFT: - rs->point_texcoord_top = 1.0f; - rs->point_texcoord_bottom = 0.0f; + point_texcoord_top = 1.0f; + point_texcoord_bottom = 0.0f; break; } } + /* Build the main command buffer. */ + BEGIN_CB(rs->cb_main, 25); + OUT_CB_REG(R300_VAP_CNTL_STATUS, vap_control_status); + OUT_CB_REG(R300_GA_POINT_SIZE, point_size); + OUT_CB_REG_SEQ(R300_GA_POINT_MINMAX, 2); + OUT_CB(point_minmax); + OUT_CB(line_control); + OUT_CB_REG_SEQ(R300_SU_POLY_OFFSET_ENABLE, 2); + OUT_CB(polygon_offset_enable); + rs->cull_mode_index = 9; + OUT_CB(cull_mode); + OUT_CB_REG(R300_GA_LINE_STIPPLE_CONFIG, line_stipple_config); + OUT_CB_REG(R300_GA_LINE_STIPPLE_VALUE, line_stipple_value); + OUT_CB_REG(R300_GA_POLY_MODE, polygon_mode); + OUT_CB_REG(R300_SC_CLIP_RULE, clip_rule); + OUT_CB_REG(R300_GB_ENABLE, stuffing_enable); + OUT_CB_REG_SEQ(R300_GA_POINT_S0, 4); + OUT_CB_32F(point_texcoord_left); + OUT_CB_32F(point_texcoord_bottom); + OUT_CB_32F(point_texcoord_right); + OUT_CB_32F(point_texcoord_top); + END_CB; + + /* Build the two command buffers for polygon offset setup. */ + if (polygon_offset_enable) { + float scale = state->offset_scale * 12; + float offset = state->offset_units * 4; + + BEGIN_CB(rs->cb_poly_offset_zb16, 5); + OUT_CB_REG_SEQ(R300_SU_POLY_OFFSET_FRONT_SCALE, 4); + OUT_CB_32F(scale); + OUT_CB_32F(offset); + OUT_CB_32F(scale); + OUT_CB_32F(offset); + END_CB; + + offset = state->offset_units * 2; + + BEGIN_CB(rs->cb_poly_offset_zb24, 5); + OUT_CB_REG_SEQ(R300_SU_POLY_OFFSET_FRONT_SCALE, 4); + OUT_CB_32F(scale); + OUT_CB_32F(offset); + OUT_CB_32F(scale); + OUT_CB_32F(offset); + END_CB; + } + return (void*)rs; } @@ -899,7 +1092,7 @@ static void r300_bind_rs_state(struct pipe_context* pipe, void* state) } UPDATE_STATE(state, r300->rs_state); - r300->rs_state.size = 27 + (r300->polygon_offset_enabled ? 5 : 0); + r300->rs_state.size = 25 + (r300->polygon_offset_enabled ? 5 : 0); if (last_sprite_coord_enable != r300->sprite_coord_enable || last_two_sided_color != r300->two_sided_color) { @@ -925,10 +1118,34 @@ static void* sampler->state = *state; + /* r300 doesn't handle CLAMP and MIRROR_CLAMP correctly when either MAG + * or MIN filter is NEAREST. Since texwrap produces same results + * for CLAMP and CLAMP_TO_EDGE, we use them instead. */ + if (sampler->state.min_img_filter == PIPE_TEX_FILTER_NEAREST || + sampler->state.mag_img_filter == PIPE_TEX_FILTER_NEAREST) { + /* Wrap S. */ + if (sampler->state.wrap_s == PIPE_TEX_WRAP_CLAMP) + sampler->state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + else if (sampler->state.wrap_s == PIPE_TEX_WRAP_MIRROR_CLAMP) + sampler->state.wrap_s = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + + /* Wrap T. */ + if (sampler->state.wrap_t == PIPE_TEX_WRAP_CLAMP) + sampler->state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + else if (sampler->state.wrap_t == PIPE_TEX_WRAP_MIRROR_CLAMP) + sampler->state.wrap_t = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + + /* Wrap R. */ + if (sampler->state.wrap_r == PIPE_TEX_WRAP_CLAMP) + sampler->state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + else if (sampler->state.wrap_r == PIPE_TEX_WRAP_MIRROR_CLAMP) + sampler->state.wrap_r = PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; + } + sampler->filter0 |= - (r300_translate_wrap(state->wrap_s) << R300_TX_WRAP_S_SHIFT) | - (r300_translate_wrap(state->wrap_t) << R300_TX_WRAP_T_SHIFT) | - (r300_translate_wrap(state->wrap_r) << R300_TX_WRAP_R_SHIFT); + (r300_translate_wrap(sampler->state.wrap_s) << R300_TX_WRAP_S_SHIFT) | + (r300_translate_wrap(sampler->state.wrap_t) << R300_TX_WRAP_T_SHIFT) | + (r300_translate_wrap(sampler->state.wrap_r) << R300_TX_WRAP_R_SHIFT); sampler->filter0 |= r300_translate_tex_filters(state->min_img_filter, state->mag_img_filter, @@ -995,6 +1212,31 @@ static void r300_delete_sampler_state(struct pipe_context* pipe, void* state) FREE(state); } +static uint32_t r300_assign_texture_cache_region(unsigned index, unsigned num) +{ + /* This looks like a hack, but I believe it's suppose to work like + * that. To illustrate how this works, let's assume you have 5 textures. + * From docs, 5 and the successive numbers are: + * + * FOURTH_1 = 5 + * FOURTH_2 = 6 + * FOURTH_3 = 7 + * EIGHTH_0 = 8 + * EIGHTH_1 = 9 + * + * First 3 textures will get 3/4 of size of the cache, divived evenly + * between them. The last 1/4 of the cache must be divided between + * the last 2 textures, each will therefore get 1/8 of the cache. + * Why not just to use "5 + texture_index" ? + * + * This simple trick works for all "num" <= 16. + */ + if (num <= 1) + return R300_TX_CACHE(R300_TX_CACHE_WHOLE); + else + return R300_TX_CACHE(num + index); +} + static void r300_set_fragment_sampler_views(struct pipe_context* pipe, unsigned count, struct pipe_sampler_view** views) @@ -1003,7 +1245,7 @@ static void r300_set_fragment_sampler_views(struct pipe_context* pipe, struct r300_textures_state* state = (struct r300_textures_state*)r300->textures_state.state; struct r300_texture *texture; - unsigned i; + unsigned i, real_num_views = 0, view_index = 0; unsigned tex_units = r300->screen->caps.num_tex_units; boolean dirty_tex = FALSE; @@ -1011,6 +1253,12 @@ static void r300_set_fragment_sampler_views(struct pipe_context* pipe, return; } + /* Calculate the real number of views. */ + for (i = 0; i < count; i++) { + if (views[i]) + real_num_views++; + } + for (i = 0; i < count; i++) { if (&state->sampler_views[i]->base != views[i]) { pipe_sampler_view_reference( @@ -1030,6 +1278,10 @@ static void r300_set_fragment_sampler_views(struct pipe_context* pipe, if (texture->uses_pitch) { r300->fs_rc_constant_state.dirty = TRUE; } + + state->sampler_views[i]->texcache_region = + r300_assign_texture_cache_region(view_index, real_num_views); + view_index++; } } @@ -1167,15 +1419,15 @@ static void r300_set_vertex_buffers(struct pipe_context* pipe, if (r300->screen->caps.has_tcl) { /* HW TCL. */ - /* Check if the stride is aligned to the size of DWORD. */ + r300->incompatible_vb_layout = FALSE; + + /* Check if the strides and offsets are aligned to the size of DWORD. */ for (i = 0; i < count; i++) { if (buffers[i].buffer) { - if (buffers[i].stride % 4 != 0) { - // XXX Shouldn't we align the buffer? - fprintf(stderr, "r300: set_vertex_buffers: " - "Unaligned buffer stride %i isn't supported.\n", - buffers[i].stride); - abort(); + if (buffers[i].stride % 4 != 0 || + buffers[i].buffer_offset % 4 != 0) { + r300->incompatible_vb_layout = TRUE; + break; } } } @@ -1248,7 +1500,7 @@ static void r300_vertex_psc(struct r300_vertex_element_state *velems) * so PSC should just route stuff based on the vertex elements, * and not on attrib information. */ for (i = 0; i < velems->count; i++) { - format = velems->velem[i].src_format; + format = velems->hw_format[i]; type = r300_translate_vertex_data_type(format); if (type == R300_INVALID_FORMAT) { @@ -1280,12 +1532,15 @@ static void r300_vertex_psc(struct r300_vertex_element_state *velems) vstream->count = (i >> 1) + 1; } +#define FORMAT_REPLACE(what, withwhat) \ + case PIPE_FORMAT_##what: *format = PIPE_FORMAT_##withwhat; break + static void* r300_create_vertex_elements_state(struct pipe_context* pipe, unsigned count, const struct pipe_vertex_element* attribs) { struct r300_vertex_element_state *velems; - unsigned i, size; + unsigned i; enum pipe_format *format; assert(count <= PIPE_MAX_ATTRIBS); @@ -1295,86 +1550,68 @@ static void* r300_create_vertex_elements_state(struct pipe_context* pipe, memcpy(velems->velem, attribs, sizeof(struct pipe_vertex_element) * count); if (r300_screen(pipe->screen)->caps.has_tcl) { - r300_vertex_psc(velems); - - /* Check if the format is aligned to the size of DWORD. - * We only care about the blocksizes of the formats since - * swizzles are already set up. */ + /* Set the best hw format in case the original format is not + * supported by hw. */ for (i = 0; i < count; i++) { - format = &velems->velem[i].src_format; + velems->hw_format[i] = velems->velem[i].src_format; + format = &velems->hw_format[i]; - /* Replace some formats with their aligned counterparts, - * this is OK because we check for aligned strides too. */ + /* This is basically the list of unsupported formats. + * For now we don't care about the alignment, that's going to + * be sorted out after the PSC setup. */ switch (*format) { - /* Align to RGBA8. */ - case PIPE_FORMAT_R8_UNORM: - case PIPE_FORMAT_R8G8_UNORM: - case PIPE_FORMAT_R8G8B8_UNORM: - *format = PIPE_FORMAT_R8G8B8A8_UNORM; - continue; - case PIPE_FORMAT_R8_SNORM: - case PIPE_FORMAT_R8G8_SNORM: - case PIPE_FORMAT_R8G8B8_SNORM: - *format = PIPE_FORMAT_R8G8B8A8_SNORM; - continue; - case PIPE_FORMAT_R8_USCALED: - case PIPE_FORMAT_R8G8_USCALED: - case PIPE_FORMAT_R8G8B8_USCALED: - *format = PIPE_FORMAT_R8G8B8A8_USCALED; - continue; - case PIPE_FORMAT_R8_SSCALED: - case PIPE_FORMAT_R8G8_SSCALED: - case PIPE_FORMAT_R8G8B8_SSCALED: - *format = PIPE_FORMAT_R8G8B8A8_SSCALED; - continue; - - /* Align to RG16. */ - case PIPE_FORMAT_R16_UNORM: - *format = PIPE_FORMAT_R16G16_UNORM; - continue; - case PIPE_FORMAT_R16_SNORM: - *format = PIPE_FORMAT_R16G16_SNORM; - continue; - case PIPE_FORMAT_R16_USCALED: - *format = PIPE_FORMAT_R16G16_USCALED; - continue; - case PIPE_FORMAT_R16_SSCALED: - *format = PIPE_FORMAT_R16G16_SSCALED; - continue; - case PIPE_FORMAT_R16_FLOAT: - *format = PIPE_FORMAT_R16G16_FLOAT; - continue; - - /* Align to RGBA16. */ - case PIPE_FORMAT_R16G16B16_UNORM: - *format = PIPE_FORMAT_R16G16B16A16_UNORM; - continue; - case PIPE_FORMAT_R16G16B16_SNORM: - *format = PIPE_FORMAT_R16G16B16A16_SNORM; - continue; - case PIPE_FORMAT_R16G16B16_USCALED: - *format = PIPE_FORMAT_R16G16B16A16_USCALED; - continue; - case PIPE_FORMAT_R16G16B16_SSCALED: - *format = PIPE_FORMAT_R16G16B16A16_SSCALED; - continue; - case PIPE_FORMAT_R16G16B16_FLOAT: - *format = PIPE_FORMAT_R16G16B16A16_FLOAT; - continue; + FORMAT_REPLACE(R64_FLOAT, R32_FLOAT); + FORMAT_REPLACE(R64G64_FLOAT, R32G32_FLOAT); + FORMAT_REPLACE(R64G64B64_FLOAT, R32G32B32_FLOAT); + FORMAT_REPLACE(R64G64B64A64_FLOAT, R32G32B32A32_FLOAT); + + FORMAT_REPLACE(R32_UNORM, R32_FLOAT); + FORMAT_REPLACE(R32G32_UNORM, R32G32_FLOAT); + FORMAT_REPLACE(R32G32B32_UNORM, R32G32B32_FLOAT); + FORMAT_REPLACE(R32G32B32A32_UNORM, R32G32B32A32_FLOAT); + + FORMAT_REPLACE(R32_USCALED, R32_FLOAT); + FORMAT_REPLACE(R32G32_USCALED, R32G32_FLOAT); + FORMAT_REPLACE(R32G32B32_USCALED, R32G32B32_FLOAT); + FORMAT_REPLACE(R32G32B32A32_USCALED,R32G32B32A32_FLOAT); + + FORMAT_REPLACE(R32_SNORM, R32_FLOAT); + FORMAT_REPLACE(R32G32_SNORM, R32G32_FLOAT); + FORMAT_REPLACE(R32G32B32_SNORM, R32G32B32_FLOAT); + FORMAT_REPLACE(R32G32B32A32_SNORM, R32G32B32A32_FLOAT); + + FORMAT_REPLACE(R32_SSCALED, R32_FLOAT); + FORMAT_REPLACE(R32G32_SSCALED, R32G32_FLOAT); + FORMAT_REPLACE(R32G32B32_SSCALED, R32G32B32_FLOAT); + FORMAT_REPLACE(R32G32B32A32_SSCALED,R32G32B32A32_FLOAT); + + FORMAT_REPLACE(R32_FIXED, R32_FLOAT); + FORMAT_REPLACE(R32G32_FIXED, R32G32_FLOAT); + FORMAT_REPLACE(R32G32B32_FIXED, R32G32B32_FLOAT); + FORMAT_REPLACE(R32G32B32A32_FIXED, R32G32B32A32_FLOAT); default:; } - size = util_format_get_blocksize(*format); + velems->incompatible_layout = + velems->incompatible_layout || + velems->velem[i].src_format != velems->hw_format[i] || + velems->velem[i].src_offset % 4 != 0; + } - if (size % 4 != 0) { - /* XXX Shouldn't we align the format? */ - fprintf(stderr, "r300_create_vertex_elements_state: " - "Unaligned format %s:%i isn't supported\n", - util_format_short_name(*format), size); - assert(0); - abort(); - } + /* Now setup PSC. + * The unused components will be replaced by (..., 0, 1). */ + r300_vertex_psc(velems); + + /* Align the formats to the size of DWORD. + * We only care about the blocksizes of the formats since + * swizzles are already set up. + * Also compute the vertex size. */ + for (i = 0; i < count; i++) { + /* This is OK because we check for aligned strides too. */ + velems->hw_format_size[i] = + align(util_format_get_blocksize(velems->hw_format[i]), 4); + velems->vertex_size_dwords += velems->hw_format_size[i] / 4; } } } @@ -1412,7 +1649,6 @@ static void* r300_create_vs_state(struct pipe_context* pipe, const struct pipe_shader_state* shader) { struct r300_context* r300 = r300_context(pipe); - struct r300_vertex_shader* vs = CALLOC_STRUCT(r300_vertex_shader); /* Copy state directly into shader. */ @@ -1490,7 +1726,7 @@ static void r300_set_constant_buffer(struct pipe_context *pipe, struct r300_context* r300 = r300_context(pipe); struct r300_constant_buffer *cbuf; struct pipe_transfer *tr; - void *mapped; + float *mapped; int max_size = 0, max_size_bytes = 0, clamped_size = 0; switch (shader) { @@ -1529,10 +1765,20 @@ static void r300_set_constant_buffer(struct pipe_context *pipe, fprintf(stderr, "r300: Max size of the constant buffer is " "%i*4 floats.\n", max_size); } - clamped_size = MIN2(buf->width0, max_size_bytes); - memcpy(cbuf->constants, mapped, clamped_size); + clamped_size = MIN2(buf->width0, max_size_bytes); cbuf->count = clamped_size / (4 * sizeof(float)); + + if (shader == PIPE_SHADER_FRAGMENT && !r300->screen->caps.is_r500) { + unsigned i,j; + + /* Convert constants to float24. */ + for (i = 0; i < cbuf->count; i++) + for (j = 0; j < 4; j++) + cbuf->constants[i][j] = pack_float24(mapped[i*4+j]); + } else { + memcpy(cbuf->constants, mapped, clamped_size); + } } if (shader == PIPE_SHADER_VERTEX) { diff --git a/src/gallium/drivers/r300/r300_state.h b/src/gallium/drivers/r300/r300_state.h deleted file mode 100644 index 1d557506cf3..00000000000 --- a/src/gallium/drivers/r300/r300_state.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2008 Marek Olšák <[email protected]> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#ifndef R300_STATE_H -#define R300_STATE_H - -struct r300_context; - -void r300_mark_fs_code_dirty(struct r300_context *r300); - -#endif /* R300_STATE_H */ diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c index cc75fad3bb9..3aa8deb63c8 100644 --- a/src/gallium/drivers/r300/r300_state_derived.c +++ b/src/gallium/drivers/r300/r300_state_derived.c @@ -31,7 +31,6 @@ #include "r300_hyperz.h" #include "r300_screen.h" #include "r300_shader_semantics.h" -#include "r300_state.h" #include "r300_state_derived.h" #include "r300_state_inlines.h" #include "r300_texture.h" @@ -537,6 +536,10 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300) UTIL_FORMAT_SWIZZLE_X }; + /* The KIL opcode fix, see below. */ + if (!count && !r300->screen->caps.is_r500) + count = 1; + state->tx_enable = 0; state->count = 0; size = 2; @@ -555,6 +558,9 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300) texstate->filter1 = sampler->filter1; texstate->border_color = sampler->border_color; + /* Assign a texture cache region. */ + texstate->format.format1 |= view->texcache_region; + /* If compare mode is disabled, the sampler view swizzles * are stored in the format. * Otherwise, swizzles must be applied after the compare mode @@ -613,6 +619,36 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300) size += 16; state->count = i+1; + } else { + /* For the KIL opcode to work on r3xx-r4xx, the texture unit + * assigned to this opcode (it's always the first one) must be + * enabled. Otherwise the opcode doesn't work. + * + * In order to not depend on the fragment shader, we just make + * the first unit enabled all the time. */ + if (i == 0 && !r300->screen->caps.is_r500) { + pipe_sampler_view_reference( + (struct pipe_sampler_view**)&state->sampler_views[i], + &r300->texkill_sampler->base); + + state->tx_enable |= 1 << i; + + texstate = &state->regs[i]; + + /* Just set some valid state. */ + texstate->format = r300->texkill_sampler->format; + texstate->filter0 = + r300_translate_tex_filters(PIPE_TEX_FILTER_NEAREST, + PIPE_TEX_FILTER_NEAREST, + PIPE_TEX_FILTER_NEAREST, + FALSE); + texstate->filter1 = 0; + texstate->border_color = 0; + + texstate->filter0 |= i << 28; + size += 16; + state->count = i+1; + } } } diff --git a/src/gallium/drivers/r300/r300_state_invariant.c b/src/gallium/drivers/r300/r300_state_invariant.c deleted file mode 100644 index 34d3a169d57..00000000000 --- a/src/gallium/drivers/r300/r300_state_invariant.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2009 Joakim Sindholt <[email protected]> - * Corbin Simpson <[email protected]> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#include "r300_context.h" -#include "r300_cs.h" -#include "r300_reg.h" -#include "r300_screen.h" -#include "r300_state_invariant.h" - -/* Calculate and emit invariant state. This is data that the 3D engine - * will probably want at the beginning of every CS, but it's not currently - * handled by any CSO setup, and in addition it doesn't really change much. - * - * Note that eventually this should be empty, but it's useful for development - * and general unduplication of code. */ -void r300_emit_invariant_state(struct r300_context* r300, - unsigned size, void* state) -{ - CS_LOCALS(r300); - - if (r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0)) { - /* Subpixel multisampling for AA. */ - BEGIN_CS(4); - OUT_CS_REG(R300_GB_MSPOS0, 0x66666666); - OUT_CS_REG(R300_GB_MSPOS1, 0x6666666); - END_CS; - } - - BEGIN_CS(12 + (r300->screen->caps.has_tcl ? 2 : 0)); - - /*** Graphics Backend (GB) ***/ - /* Source of fog depth */ - OUT_CS_REG(R300_GB_SELECT, R300_GB_FOG_SELECT_1_1_W); - - /*** Fog (FG) ***/ - OUT_CS_REG(R300_FG_FOG_BLEND, 0x0); - OUT_CS_REG(R300_FG_FOG_COLOR_R, 0x0); - OUT_CS_REG(R300_FG_FOG_COLOR_G, 0x0); - OUT_CS_REG(R300_FG_FOG_COLOR_B, 0x0); - - /*** VAP ***/ - /* Sign/normalize control */ - OUT_CS_REG(R300_VAP_PSC_SGN_NORM_CNTL, R300_SGN_NORM_NO_ZERO); - /* TCL-only stuff */ - if (r300->screen->caps.has_tcl) { - /* Amount of time to wait for vertex fetches in PVS */ - OUT_CS_REG(VAP_PVS_VTX_TIMEOUT_REG, 0xffff); - } - - END_CS; - - /* XXX unsorted stuff from surface_fill */ - BEGIN_CS(38 + (r300->screen->caps.has_tcl ? 7 : 0) + - (r300->screen->caps.is_rv350 ? 4 : 0)); - - if (r300->screen->caps.has_tcl) { - /*Flushing PVS is required before the VAP_GB registers can be changed*/ - OUT_CS_REG(R300_VAP_PVS_STATE_FLUSH_REG, 0); - OUT_CS_REG_SEQ(R300_VAP_GB_VERT_CLIP_ADJ, 4); - OUT_CS_32F(1.0); - OUT_CS_32F(1.0); - OUT_CS_32F(1.0); - OUT_CS_32F(1.0); - } - /* XXX line tex stuffing */ - OUT_CS_REG_SEQ(R300_GA_LINE_S0, 1); - OUT_CS_32F(0.0); - OUT_CS_REG_SEQ(R300_GA_LINE_S1, 1); - OUT_CS_32F(1.0); - OUT_CS_REG(R300_GA_TRIANGLE_STIPPLE, 0x5 | - (0x5 << R300_GA_TRIANGLE_STIPPLE_Y_SHIFT_SHIFT)); - /* XXX this big chunk should be refactored into rs_state */ - OUT_CS_REG(R300_GA_SOLID_RG, 0x00000000); - OUT_CS_REG(R300_GA_SOLID_BA, 0x00000000); - OUT_CS_REG(R300_GA_ROUND_MODE, 0x00000001); - OUT_CS_REG(R300_GA_OFFSET, 0x00000000); - OUT_CS_REG(R300_GA_FOG_SCALE, 0x3DBF1412); - OUT_CS_REG(R300_GA_FOG_OFFSET, 0x00000000); - OUT_CS_REG(R300_SU_TEX_WRAP, 0x00000000); - OUT_CS_REG(R300_SU_DEPTH_SCALE, 0x4B7FFFFF); - OUT_CS_REG(R300_SU_DEPTH_OFFSET, 0x00000000); - OUT_CS_REG(R300_SC_HYPERZ, 0x0000001C); - OUT_CS_REG(R300_SC_EDGERULE, 0x2DA49525); - OUT_CS_REG(R300_RB3D_AARESOLVE_CTL, 0x00000000); - - if (r300->screen->caps.is_rv350) { - OUT_CS_REG(R500_RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD, 0x01010101); - OUT_CS_REG(R500_RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD, 0xFEFEFEFE); - } - - OUT_CS_REG(R300_ZB_BW_CNTL, 0x00000000); - OUT_CS_REG(R300_ZB_DEPTHCLEARVALUE, 0x00000000); - OUT_CS_REG(R300_ZB_HIZ_OFFSET, 0x00000000); - OUT_CS_REG(R300_ZB_HIZ_PITCH, 0x00000000); - END_CS; -} diff --git a/src/gallium/drivers/r300/r300_state_invariant.h b/src/gallium/drivers/r300/r300_state_invariant.h deleted file mode 100644 index 83d031c7fe9..00000000000 --- a/src/gallium/drivers/r300/r300_state_invariant.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2008 Corbin Simpson <[email protected]> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * on the rights to use, copy, modify, merge, publish, distribute, sub - * license, and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#ifndef R300_STATE_INVARIANT_H -#define R300_STATE_INVARIANT_H - -struct r300_context; - -void r300_emit_invariant_state(struct r300_context* r300, - unsigned size, void* state); - -#endif /* R300_STATE_INVARIANT_H */ diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c index 5a013e2a25a..6206570fca4 100644 --- a/src/gallium/drivers/r300/r300_texture.c +++ b/src/gallium/drivers/r300/r300_texture.c @@ -21,30 +21,28 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "pipe/p_screen.h" - -#include "util/u_format.h" -#include "util/u_format_s3tc.h" -#include "util/u_math.h" -#include "util/u_memory.h" +/* Always include headers in the reverse order!! ~ M. */ +#include "r300_texture.h" #include "r300_context.h" #include "r300_reg.h" -#include "r300_texture.h" #include "r300_transfer.h" #include "r300_screen.h" #include "r300_winsys.h" -#define TILE_WIDTH 0 -#define TILE_HEIGHT 1 +#include "util/u_format.h" +#include "util/u_format_s3tc.h" +#include "util/u_math.h" +#include "util/u_memory.h" + +#include "pipe/p_screen.h" -static const unsigned microblock_table[5][3][2] = { - /*linear tiled square-tiled */ - {{32, 1}, {8, 4}, {0, 0}}, /* 8 bits per pixel */ - {{16, 1}, {8, 2}, {4, 4}}, /* 16 bits per pixel */ - {{ 8, 1}, {4, 2}, {0, 0}}, /* 32 bits per pixel */ - {{ 4, 1}, {0, 0}, {2, 2}}, /* 64 bits per pixel */ - {{ 2, 1}, {0, 0}, {0, 0}} /* 128 bits per pixel */ +/* XXX NO! just no! */ +#include "state_tracker/drm_driver.h" + +enum r300_dim { + DIM_WIDTH = 0, + DIM_HEIGHT = 1 }; unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format, @@ -596,21 +594,21 @@ static void r300_texture_setup_fb_state(struct r300_screen* screen, /* Set framebuffer state. */ if (util_format_is_depth_or_stencil(tex->b.b.format)) { for (i = 0; i <= tex->b.b.last_level; i++) { - tex->fb_state.depthpitch[i] = + tex->fb_state.pitch[i] = tex->hwpitch[i] | R300_DEPTHMACROTILE(tex->mip_macrotile[i]) | R300_DEPTHMICROTILE(tex->microtile); } - tex->fb_state.zb_format = r300_translate_zsformat(tex->b.b.format); + tex->fb_state.format = r300_translate_zsformat(tex->b.b.format); } else { for (i = 0; i <= tex->b.b.last_level; i++) { - tex->fb_state.colorpitch[i] = + tex->fb_state.pitch[i] = tex->hwpitch[i] | r300_translate_colorformat(tex->b.b.format) | R300_COLOR_TILE(tex->mip_macrotile[i]) | R300_COLOR_MICROTILE(tex->microtile); } - tex->fb_state.us_out_fmt = r300_translate_out_fmt(tex->b.b.format); + tex->fb_state.format = r300_translate_out_fmt(tex->b.b.format); } } @@ -620,8 +618,10 @@ void r300_texture_reinterpret_format(struct pipe_screen *screen, { struct r300_screen *r300screen = r300_screen(screen); - SCREEN_DBG(r300screen, DBG_TEX, "r300: texture_reinterpret_format: %s -> %s\n", - util_format_short_name(tex->format), util_format_short_name(new_format)); + SCREEN_DBG(r300screen, DBG_TEX, + "r300: texture_reinterpret_format: %s -> %s\n", + util_format_short_name(tex->format), + util_format_short_name(new_format)); tex->format = new_format; @@ -648,36 +648,65 @@ unsigned r300_texture_get_offset(struct r300_texture* tex, unsigned level, } } -/** - * Return the width (dim==TILE_WIDTH) or height (dim==TILE_HEIGHT) of one tile - * of the given texture. - */ -static unsigned r300_texture_get_tile_size(struct r300_texture* tex, - int dim, boolean macrotile) +/* Returns the number of pixels that the texture should be aligned to + * in the given dimension. */ +static unsigned r300_get_pixel_alignment(struct r300_texture *tex, + enum r300_buffer_tiling macrotile, + enum r300_dim dim) { - unsigned pixsize, tile_size; - - pixsize = util_format_get_blocksize(tex->b.b.format); - tile_size = microblock_table[util_logbase2(pixsize)][tex->microtile][dim]; - - if (macrotile) { - tile_size *= 8; + static const unsigned table[2][5][3][2] = + { + { + /* Macro: linear linear linear + Micro: linear tiled square-tiled */ + {{ 32, 1}, { 8, 4}, { 0, 0}}, /* 8 bits per pixel */ + {{ 16, 1}, { 8, 2}, { 4, 4}}, /* 16 bits per pixel */ + {{ 8, 1}, { 4, 2}, { 0, 0}}, /* 32 bits per pixel */ + {{ 4, 1}, { 0, 0}, { 2, 2}}, /* 64 bits per pixel */ + {{ 2, 1}, { 0, 0}, { 0, 0}} /* 128 bits per pixel */ + }, + { + /* Macro: tiled tiled tiled + Micro: linear tiled square-tiled */ + {{256, 8}, {64, 32}, { 0, 0}}, /* 8 bits per pixel */ + {{128, 8}, {64, 16}, {32, 32}}, /* 16 bits per pixel */ + {{ 64, 8}, {32, 16}, { 0, 0}}, /* 32 bits per pixel */ + {{ 32, 8}, { 0, 0}, {16, 16}}, /* 64 bits per pixel */ + {{ 16, 8}, { 0, 0}, { 0, 0}} /* 128 bits per pixel */ + } + }; + static const unsigned aa_block[2] = {4, 8}; + unsigned res = 0; + unsigned pixsize = util_format_get_blocksize(tex->b.b.format); + + assert(macrotile <= R300_BUFFER_TILED); + assert(tex->microtile <= R300_BUFFER_SQUARETILED); + assert(pixsize <= 16); + assert(dim <= DIM_HEIGHT); + + if (tex->b.b.nr_samples > 1) { + /* Multisampled textures have their own alignment scheme. */ + if (pixsize == 4) + res = aa_block[dim]; + } else { + /* Standard alignment. */ + res = table[macrotile][util_logbase2(pixsize)][tex->microtile][dim]; } - assert(tile_size); - return tile_size; + assert(res); + return res; } /* Return true if macrotiling should be enabled on the miplevel. */ static boolean r300_texture_macro_switch(struct r300_texture *tex, unsigned level, boolean rv350_mode, - int dim) + enum r300_dim dim) { unsigned tile, texdim; - tile = r300_texture_get_tile_size(tex, dim, TRUE); - if (dim == TILE_WIDTH) { + tile = r300_get_pixel_alignment(tex, R300_BUFFER_TILED, dim); + if (dim == DIM_WIDTH) { texdim = u_minify(tex->b.b.width0, level); } else { texdim = u_minify(tex->b.b.height0, level); @@ -713,8 +742,8 @@ unsigned r300_texture_get_stride(struct r300_screen* screen, width = u_minify(tex->b.b.width0, level); if (util_format_is_plain(tex->b.b.format)) { - tile_width = r300_texture_get_tile_size(tex, TILE_WIDTH, - tex->mip_macrotile[level]); + tile_width = r300_get_pixel_alignment(tex, tex->mip_macrotile[level], + DIM_WIDTH); width = align(width, tile_width); stride = util_format_get_stride(tex->b.b.format, width); @@ -743,8 +772,8 @@ static unsigned r300_texture_get_nblocksy(struct r300_texture* tex, height = u_minify(tex->b.b.height0, level); if (util_format_is_plain(tex->b.b.format)) { - tile_height = r300_texture_get_tile_size(tex, TILE_HEIGHT, - tex->mip_macrotile[level]); + tile_height = r300_get_pixel_alignment(tex, tex->mip_macrotile[level], + DIM_HEIGHT); height = align(height, tile_height); /* This is needed for the kernel checker, unfortunately. */ @@ -784,21 +813,26 @@ static void r300_setup_miptree(struct r300_screen* screen, unsigned stride, size, layer_size, nblocksy, i; boolean rv350_mode = screen->caps.is_rv350; - SCREEN_DBG(screen, DBG_TEXALLOC, "r300: Making miptree for texture, format %s\n", - util_format_short_name(base->format)); + SCREEN_DBG(screen, DBG_TEXALLOC, + "r300: Making miptree for texture, format %s\n", + util_format_short_name(base->format)); for (i = 0; i <= base->last_level; i++) { /* Let's see if this miplevel can be macrotiled. */ tex->mip_macrotile[i] = (tex->macrotile == R300_BUFFER_TILED && - r300_texture_macro_switch(tex, i, rv350_mode, TILE_WIDTH) && - r300_texture_macro_switch(tex, i, rv350_mode, TILE_HEIGHT)) ? + r300_texture_macro_switch(tex, i, rv350_mode, DIM_WIDTH) && + r300_texture_macro_switch(tex, i, rv350_mode, DIM_HEIGHT)) ? R300_BUFFER_TILED : R300_BUFFER_LINEAR; stride = r300_texture_get_stride(screen, tex, i); nblocksy = r300_texture_get_nblocksy(tex, i); layer_size = stride * nblocksy; + if (base->nr_samples) { + layer_size *= base->nr_samples; + } + if (base->target == PIPE_TEXTURE_CUBE) size = layer_size * 6; else @@ -864,8 +898,8 @@ static void r300_setup_tiling(struct pipe_screen *screen, } /* Set macrotiling. */ - if (r300_texture_macro_switch(tex, 0, rv350_mode, TILE_WIDTH) && - r300_texture_macro_switch(tex, 0, rv350_mode, TILE_HEIGHT)) { + if (r300_texture_macro_switch(tex, 0, rv350_mode, DIM_WIDTH) && + r300_texture_macro_switch(tex, 0, rv350_mode, DIM_HEIGHT)) { tex->macrotile = R300_BUFFER_TILED; } } @@ -899,17 +933,14 @@ static boolean r300_texture_get_handle(struct pipe_screen* screen, { struct r300_winsys_screen *rws = (struct r300_winsys_screen *)screen->winsys; struct r300_texture* tex = (struct r300_texture*)texture; - unsigned stride; if (!tex) { return FALSE; } - stride = r300_texture_get_stride(r300_screen(screen), tex, 0); - - rws->buffer_get_handle(rws, tex->buffer, stride, whandle); + whandle->stride = r300_texture_get_stride(r300_screen(screen), tex, 0); - return TRUE; + return rws->buffer_get_handle(rws, tex->buffer, whandle); } struct u_resource_vtbl r300_texture_vtbl = @@ -966,11 +997,12 @@ struct pipe_resource* r300_texture_create(struct pipe_screen* screen, SCREEN_DBG(rscreen, DBG_TEX, "r300: texture_create: Macro: %s, Micro: %s, Pitch: %i, " - "Dim: %ix%ix%i, LastLevel: %i, Format: %s\n", + "Dim: %ix%ix%i, LastLevel: %i, Size: %i, Format: %s\n", tex->macrotile ? "YES" : " NO", tex->microtile ? "YES" : " NO", tex->hwpitch[0], base->width0, base->height0, base->depth0, base->last_level, + tex->size, util_format_short_name(base->format)); tex->domain = base->flags & R300_RESOURCE_FLAG_TRANSFER ? R300_DOMAIN_GTT : @@ -979,16 +1011,16 @@ struct pipe_resource* r300_texture_create(struct pipe_screen* screen, tex->buffer = rws->buffer_create(rws, 2048, base->bind, tex->domain, tex->size); + if (!tex->buffer) { + FREE(tex); + return NULL; + } + rws->buffer_set_tiling(rws, tex->buffer, tex->pitch[0] * util_format_get_blocksize(tex->b.b.format), tex->microtile, tex->macrotile); - if (!tex->buffer) { - FREE(tex); - return NULL; - } - return (struct pipe_resource*)tex; } @@ -1002,26 +1034,27 @@ struct pipe_surface* r300_get_tex_surface(struct pipe_screen* screen, unsigned flags) { struct r300_texture* tex = r300_texture(texture); - struct pipe_surface* surface = CALLOC_STRUCT(pipe_surface); - unsigned offset; - - offset = r300_texture_get_offset(tex, level, zslice, face); + struct r300_surface* surface = CALLOC_STRUCT(r300_surface); if (surface) { - pipe_reference_init(&surface->reference, 1); - pipe_resource_reference(&surface->texture, texture); - surface->format = texture->format; - surface->width = u_minify(texture->width0, level); - surface->height = u_minify(texture->height0, level); - surface->offset = offset; - surface->usage = flags; - surface->zslice = zslice; - surface->texture = texture; - surface->face = face; - surface->level = level; + pipe_reference_init(&surface->base.reference, 1); + pipe_resource_reference(&surface->base.texture, texture); + surface->base.format = texture->format; + surface->base.width = u_minify(texture->width0, level); + surface->base.height = u_minify(texture->height0, level); + surface->base.usage = flags; + surface->base.zslice = zslice; + surface->base.face = face; + surface->base.level = level; + + surface->buffer = tex->buffer; + surface->domain = tex->domain; + surface->offset = r300_texture_get_offset(tex, level, zslice, face); + surface->pitch = tex->fb_state.pitch[level]; + surface->format = tex->fb_state.format; } - return surface; + return &surface->base; } /* Not required to implement u_resource_vtbl, consider moving to another file: @@ -1041,7 +1074,6 @@ r300_texture_from_handle(struct pipe_screen* screen, struct r300_screen* rscreen = r300_screen(screen); struct r300_winsys_buffer *buffer; struct r300_texture* tex; - unsigned stride; boolean override_zb_flags; /* Support only 2D textures without mipmaps */ @@ -1051,7 +1083,8 @@ r300_texture_from_handle(struct pipe_screen* screen, return NULL; } - buffer = rws->buffer_from_handle(rws, screen, whandle, &stride); + /* XXX make the winsys return the stride_override, see i915_resource_texture.c:830 */ + buffer = rws->buffer_from_handle(rws, whandle->handle); if (!buffer) { return NULL; } @@ -1067,7 +1100,7 @@ r300_texture_from_handle(struct pipe_screen* screen, tex->b.b.screen = screen; tex->domain = R300_DOMAIN_VRAM; - tex->stride_override = stride; + tex->stride_override = whandle->stride; /* one ref already taken */ tex->buffer = buffer; @@ -1079,7 +1112,7 @@ r300_texture_from_handle(struct pipe_screen* screen, "Pitch: % 4i, Dim: %ix%i, Format: %s\n", tex->macrotile ? "YES" : " NO", tex->microtile ? "YES" : " NO", - stride / util_format_get_blocksize(base->format), + whandle->stride / util_format_get_blocksize(base->format), base->width0, base->height0, util_format_short_name(base->format)); diff --git a/src/gallium/drivers/r300/r300_texture.h b/src/gallium/drivers/r300/r300_texture.h index ff640c56eed..99e7694254e 100644 --- a/src/gallium/drivers/r300/r300_texture.h +++ b/src/gallium/drivers/r300/r300_texture.h @@ -23,8 +23,11 @@ #ifndef R300_TEXTURE_H #define R300_TEXTURE_H -#include "util/u_format.h" +#include "pipe/p_format.h" +struct pipe_screen; +struct pipe_resource; +struct winsys_handle; struct r300_texture; struct r300_screen; diff --git a/src/gallium/drivers/r300/r300_tgsi_to_rc.c b/src/gallium/drivers/r300/r300_tgsi_to_rc.c index 89f39af9761..5394e04f727 100644 --- a/src/gallium/drivers/r300/r300_tgsi_to_rc.c +++ b/src/gallium/drivers/r300/r300_tgsi_to_rc.c @@ -105,12 +105,12 @@ static unsigned translate_opcode(unsigned opcode) /* case TGSI_OPCODE_DIV: return RC_OPCODE_DIV; */ /* case TGSI_OPCODE_DP2: return RC_OPCODE_DP2; */ case TGSI_OPCODE_TXL: return RC_OPCODE_TXL; - /* case TGSI_OPCODE_BRK: return RC_OPCODE_BRK; */ + case TGSI_OPCODE_BRK: return RC_OPCODE_BRK; case TGSI_OPCODE_IF: return RC_OPCODE_IF; - /* case TGSI_OPCODE_LOOP: return RC_OPCODE_LOOP; */ + case TGSI_OPCODE_BGNLOOP: return RC_OPCODE_BGNLOOP; case TGSI_OPCODE_ELSE: return RC_OPCODE_ELSE; case TGSI_OPCODE_ENDIF: return RC_OPCODE_ENDIF; - /* case TGSI_OPCODE_ENDLOOP: return RC_OPCODE_ENDLOOP; */ + case TGSI_OPCODE_ENDLOOP: return RC_OPCODE_ENDLOOP; /* case TGSI_OPCODE_PUSHA: return RC_OPCODE_PUSHA; */ /* case TGSI_OPCODE_POPA: return RC_OPCODE_POPA; */ case TGSI_OPCODE_CEIL: return RC_OPCODE_CEIL; diff --git a/src/gallium/drivers/r300/r300_transfer.c b/src/gallium/drivers/r300/r300_transfer.c index 0d88d745c07..02421a58b83 100644 --- a/src/gallium/drivers/r300/r300_transfer.c +++ b/src/gallium/drivers/r300/r300_transfer.c @@ -57,22 +57,11 @@ static void r300_copy_from_tiled_texture(struct pipe_context *ctx, subdst.face = 0; subdst.level = 0; - /* XXX if we don't flush before copying the texture and mapping it, - * we get wrong pixels, i.e. it's like latest draw calls didn't happen, - * including this blit. Tests: e.g. piglit/provoking-vertex - * - * Since the flush immediately before mapping is implicit (the buffer is - * always referenced in resource_copy_region), every read transfer costs - * 2 flushes. That sucks. */ - ctx->flush(ctx, 0, NULL); - ctx->resource_copy_region(ctx, &r300transfer->detiled_texture->b.b, subdst, 0, 0, 0, tex, transfer->sr, transfer->box.x, transfer->box.y, transfer->box.z, transfer->box.width, transfer->box.height); - - /* Flushing after the copy is implicit, issued by winsys. */ } /* Copy a detiled texture to a tiled one. */ @@ -92,7 +81,6 @@ static void r300_copy_into_tiled_texture(struct pipe_context *ctx, 0, 0, 0, transfer->box.width, transfer->box.height); - /* XXX this flush fixes a few piglit tests (e.g. glean/pixelFormats). */ ctx->flush(ctx, 0, NULL); } @@ -107,7 +95,7 @@ r300_texture_get_transfer(struct pipe_context *ctx, struct r300_screen *r300screen = r300_screen(ctx->screen); struct r300_transfer *trans; struct pipe_resource base; - boolean referenced_cs, referenced_hw; + boolean referenced_cs, referenced_hw, blittable; referenced_cs = r300screen->rws->is_buffer_referenced( r300screen->rws, tex->buffer, R300_REF_CS); @@ -118,6 +106,10 @@ r300_texture_get_transfer(struct pipe_context *ctx, r300screen->rws, tex->buffer, R300_REF_HW); } + blittable = ctx->screen->is_format_supported( + ctx->screen, texture->format, texture->target, 0, + PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET, 0); + trans = CALLOC_STRUCT(r300_transfer); if (trans) { /* Initialize the transfer object. */ @@ -130,7 +122,7 @@ r300_texture_get_transfer(struct pipe_context *ctx, * for this transfer. * Also make write transfers pipelined. */ if (tex->microtile || tex->macrotile || - (referenced_hw & !(usage & PIPE_TRANSFER_READ))) { + ((referenced_hw & !(usage & PIPE_TRANSFER_READ)) && blittable)) { base.target = PIPE_TEXTURE_2D; base.format = texture->format; base.width0 = box->width; @@ -158,6 +150,30 @@ r300_texture_get_transfer(struct pipe_context *ctx, ctx->screen->resource_create(ctx->screen, &base)); + if (!trans->detiled_texture) { + /* Oh crap, the thing can't create the texture. + * Let's flush and try again. */ + ctx->flush(ctx, 0, NULL); + + trans->detiled_texture = r300_texture( + ctx->screen->resource_create(ctx->screen, + &base)); + + if (!trans->detiled_texture) { + /* For linear textures, it's safe to fallback to + * an unpipelined transfer. */ + if (!tex->microtile && !tex->macrotile) { + goto unpipelined; + } + + /* Otherwise, go to hell. */ + fprintf(stderr, + "r300: Failed to create a transfer object, praise.\n"); + FREE(trans); + return NULL; + } + } + assert(!trans->detiled_texture->microtile && !trans->detiled_texture->macrotile); @@ -179,16 +195,20 @@ r300_texture_get_transfer(struct pipe_context *ctx, /* Always referenced in the blit. */ ctx->flush(ctx, 0, NULL); } - } else { - trans->transfer.stride = + return &trans->transfer; + } + + unpipelined: + /* Unpipelined transfer. */ + trans->transfer.stride = r300_texture_get_stride(r300screen, tex, sr.level); - trans->offset = r300_texture_get_offset(tex, sr.level, box->z, sr.face); + trans->offset = r300_texture_get_offset(tex, sr.level, box->z, sr.face); - if (referenced_cs && (usage & PIPE_TRANSFER_READ)) - ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL); - } + if (referenced_cs && (usage & PIPE_TRANSFER_READ)) + ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL); + return &trans->transfer; } - return &trans->transfer; + return NULL; } void r300_texture_transfer_destroy(struct pipe_context *ctx, diff --git a/src/gallium/drivers/r300/r300_winsys.h b/src/gallium/drivers/r300/r300_winsys.h index 8a8888d4813..3b5e9eec602 100644 --- a/src/gallium/drivers/r300/r300_winsys.h +++ b/src/gallium/drivers/r300/r300_winsys.h @@ -47,13 +47,6 @@ enum r300_reference_domain { /* bitfield */ R300_REF_HW = 2 }; -struct r300_cs_info { - /* In DWORDs. */ - unsigned used; - unsigned free; - unsigned capacity; -}; - struct r300_winsys_screen { void (*destroy)(struct r300_winsys_screen *ws); @@ -109,16 +102,13 @@ struct r300_winsys_screen { * Returns TRUE if a flush is required. */ boolean (*validate)(struct r300_winsys_screen* winsys); - /* Return current CS info. */ - void (*get_cs_info)(struct r300_winsys_screen *winsys, - struct r300_cs_info *info); + /* Return the number of free dwords in CS. */ + unsigned (*get_cs_free_dwords)(struct r300_winsys_screen *winsys); - /* Start a command emit. */ - void (*begin_cs)(struct r300_winsys_screen* winsys, - int size, - const char* file, - const char* function, - int line); + /* Return the pointer to the first free dword in CS and assume a pipe + * driver wants to fill "count" dwords. */ + uint32_t *(*get_cs_pointer)(struct r300_winsys_screen *winsys, + unsigned count); /* Write a dword to the command buffer. */ void (*write_cs_dword)(struct r300_winsys_screen* winsys, uint32_t dword); @@ -134,12 +124,6 @@ struct r300_winsys_screen { enum r300_buffer_domain wd, uint32_t flags); - /* Finish a command emit. */ - void (*end_cs)(struct r300_winsys_screen* winsys, - const char* file, - const char* function, - int line); - /* Flush the CS. */ void (*flush_cs)(struct r300_winsys_screen* winsys); @@ -164,12 +148,10 @@ struct r300_winsys_screen { enum r300_value_id vid); struct r300_winsys_buffer *(*buffer_from_handle)(struct r300_winsys_screen *winsys, - struct pipe_screen *screen, - struct winsys_handle *whandle, - unsigned *stride); + unsigned handle); + boolean (*buffer_get_handle)(struct r300_winsys_screen *winsys, struct r300_winsys_buffer *buffer, - unsigned stride, struct winsys_handle *whandle); boolean (*is_buffer_referenced)(struct r300_winsys_screen *winsys, |