diff options
Diffstat (limited to 'src/mesa')
64 files changed, 1870 insertions, 915 deletions
diff --git a/src/mesa/drivers/dri/i915/intel_pixel_read.c b/src/mesa/drivers/dri/i915/intel_pixel_read.c index 56087aacd4..cc4589f4d4 100644..120000 --- a/src/mesa/drivers/dri/i915/intel_pixel_read.c +++ b/src/mesa/drivers/dri/i915/intel_pixel_read.c @@ -1,306 +1 @@ -/************************************************************************** - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * 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 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 TUNGSTEN GRAPHICS AND/OR ITS 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 "main/glheader.h" -#include "main/enums.h" -#include "main/mtypes.h" -#include "main/macros.h" -#include "main/image.h" -#include "main/bufferobj.h" -#include "swrast/swrast.h" - -#include "intel_screen.h" -#include "intel_context.h" -#include "intel_batchbuffer.h" -#include "intel_blit.h" -#include "intel_buffers.h" -#include "intel_regions.h" -#include "intel_pixel.h" -#include "intel_buffer_objects.h" - -/* For many applications, the new ability to pull the source buffers - * back out of the GTT and then do the packing/conversion operations - * in software will be as much of an improvement as trying to get the - * blitter and/or texture engine to do the work. - * - * This step is gated on private backbuffers. - * - * Obviously the frontbuffer can't be pulled back, so that is either - * an argument for blit/texture readpixels, or for blitting to a - * temporary and then pulling that back. - * - * When the destination is a pbo, however, it's not clear if it is - * ever going to be pulled to main memory (though the access param - * will be a good hint). So it sounds like we do want to be able to - * choose between blit/texture implementation on the gpu and pullback - * and cpu-based copying. - * - * Unless you can magically turn client memory into a PBO for the - * duration of this call, there will be a cpu-based copying step in - * any case. - */ - - -static GLboolean -do_texture_readpixels(GLcontext * ctx, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *pack, - struct intel_region *dest_region) -{ -#if 0 - struct intel_context *intel = intel_context(ctx); - intelScreenPrivate *screen = intel->intelScreen; - GLint pitch = pack->RowLength ? pack->RowLength : width; - __DRIdrawablePrivate *dPriv = intel->driDrawable; - int textureFormat; - GLenum glTextureFormat; - int destFormat, depthFormat, destPitch; - drm_clip_rect_t tmp; - - if (INTEL_DEBUG & DEBUG_PIXEL) - fprintf(stderr, "%s\n", __FUNCTION__); - - - if (ctx->_ImageTransferState || - pack->SwapBytes || pack->LsbFirst || !pack->Invert) { - if (INTEL_DEBUG & DEBUG_PIXEL) - fprintf(stderr, "%s: check_color failed\n", __FUNCTION__); - return GL_FALSE; - } - - intel->vtbl.meta_texrect_source(intel, intel_readbuf_region(intel)); - - if (!intel->vtbl.meta_render_dest(intel, dest_region, type, format)) { - if (INTEL_DEBUG & DEBUG_PIXEL) - fprintf(stderr, "%s: couldn't set dest %s/%s\n", - __FUNCTION__, - _mesa_lookup_enum_by_nr(type), - _mesa_lookup_enum_by_nr(format)); - return GL_FALSE; - } - - LOCK_HARDWARE(intel); - - if (intel->driDrawable->numClipRects) { - intel->vtbl.install_meta_state(intel); - intel->vtbl.meta_no_depth_write(intel); - intel->vtbl.meta_no_stencil_write(intel); - - if (!driClipRectToFramebuffer(ctx->ReadBuffer, &x, &y, &width, &height)) { - UNLOCK_HARDWARE(intel); - SET_STATE(i830, state); - if (INTEL_DEBUG & DEBUG_PIXEL) - fprintf(stderr, "%s: cliprect failed\n", __FUNCTION__); - return GL_TRUE; - } - - y = dPriv->h - y - height; - x += dPriv->x; - y += dPriv->y; - - - /* Set the frontbuffer up as a large rectangular texture. - */ - intel->vtbl.meta_tex_rect_source(intel, src_region, textureFormat); - - - intel->vtbl.meta_texture_blend_replace(i830, glTextureFormat); - - - /* Set the 3d engine to draw into the destination region: - */ - - intel->vtbl.meta_draw_region(intel, dest_region); - intel->vtbl.meta_draw_format(intel, destFormat, depthFormat); /* ?? */ - - - /* Draw a single quad, no cliprects: - */ - intel->vtbl.meta_disable_cliprects(intel); - - intel->vtbl.draw_quad(intel, - 0, width, 0, height, - 0x00ff00ff, x, x + width, y, y + height); - - intel->vtbl.leave_meta_state(intel); - } - UNLOCK_HARDWARE(intel); - - intel_region_wait_fence(ctx, dest_region); /* required by GL */ - return GL_TRUE; -#endif - - return GL_FALSE; -} - - - - -static GLboolean -do_blit_readpixels(GLcontext * ctx, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *pack, GLvoid * pixels) -{ - struct intel_context *intel = intel_context(ctx); - struct intel_region *src = intel_readbuf_region(intel); - struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj); - GLuint dst_offset; - GLuint rowLength; - - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s\n", __FUNCTION__); - - if (!src) - return GL_FALSE; - - if (dst) { - /* XXX This validation should be done by core mesa: - */ - if (!_mesa_validate_pbo_access(2, pack, width, height, 1, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); - return GL_TRUE; - } - } - else { - /* PBO only for now: - */ - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s - not PBO\n", __FUNCTION__); - return GL_FALSE; - } - - - if (ctx->_ImageTransferState || - !intel_check_blit_format(src, format, type)) { - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s - bad format for blit\n", __FUNCTION__); - return GL_FALSE; - } - - if (pack->Alignment != 1 || pack->SwapBytes || pack->LsbFirst) { - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s: bad packing params\n", __FUNCTION__); - return GL_FALSE; - } - - if (pack->RowLength > 0) - rowLength = pack->RowLength; - else - rowLength = width; - - if (pack->Invert) { - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s: MESA_PACK_INVERT not done yet\n", __FUNCTION__); - return GL_FALSE; - } - else { - rowLength = -rowLength; - } - - /* XXX 64-bit cast? */ - dst_offset = (GLuint) _mesa_image_address(2, pack, pixels, width, height, - format, type, 0, 0, 0); - - - /* Although the blits go on the command buffer, need to do this and - * fire with lock held to guarentee cliprects are correct. - */ - intelFlush(&intel->ctx); - LOCK_HARDWARE(intel); - - if (intel->driDrawable->numClipRects) { - GLboolean all = (width * height * src->cpp == dst->Base.Size && - x == 0 && dst_offset == 0); - - dri_bo *dst_buffer = intel_bufferobj_buffer(intel, dst, - all ? INTEL_WRITE_FULL : - INTEL_WRITE_PART); - __DRIdrawablePrivate *dPriv = intel->driDrawable; - int nbox = dPriv->numClipRects; - drm_clip_rect_t *box = dPriv->pClipRects; - drm_clip_rect_t rect; - drm_clip_rect_t src_rect; - int i; - - src_rect.x1 = dPriv->x + x; - src_rect.y1 = dPriv->y + dPriv->h - (y + height); - src_rect.x2 = src_rect.x1 + width; - src_rect.y2 = src_rect.y1 + height; - - - - for (i = 0; i < nbox; i++) { - if (!intel_intersect_cliprects(&rect, &src_rect, &box[i])) - continue; - - intelEmitCopyBlit(intel, - src->cpp, - src->pitch, src->buffer, 0, src->tiling, - rowLength, dst_buffer, dst_offset, GL_FALSE, - rect.x1, - rect.y1, - rect.x1 - src_rect.x1, - rect.y2 - src_rect.y2, - rect.x2 - rect.x1, rect.y2 - rect.y1, - GL_COPY); - } - } - UNLOCK_HARDWARE(intel); - - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s - DONE\n", __FUNCTION__); - - return GL_TRUE; -} - -void -intelReadPixels(GLcontext * ctx, - GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, - const struct gl_pixelstore_attrib *pack, GLvoid * pixels) -{ - if (INTEL_DEBUG & DEBUG_PIXEL) - fprintf(stderr, "%s\n", __FUNCTION__); - - intelFlush(ctx); - - if (do_blit_readpixels - (ctx, x, y, width, height, format, type, pack, pixels)) - return; - - if (do_texture_readpixels - (ctx, x, y, width, height, format, type, pack, pixels)) - return; - - if (INTEL_DEBUG & DEBUG_PIXEL) - _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); - - _swrast_ReadPixels(ctx, x, y, width, height, format, type, pack, pixels); -} +../intel/intel_pixel_read.c
\ No newline at end of file diff --git a/src/mesa/drivers/dri/i965/Makefile b/src/mesa/drivers/dri/i965/Makefile index 9712c38725..00a42111da 100644 --- a/src/mesa/drivers/dri/i965/Makefile +++ b/src/mesa/drivers/dri/i965/Makefile @@ -23,6 +23,7 @@ DRIVER_SOURCES = \ intel_pixel_bitmap.c \ intel_pixel_copy.c \ intel_pixel_draw.c \ + intel_pixel_read.c \ intel_state.c \ intel_swapbuffers.c \ intel_tex.c \ diff --git a/src/mesa/drivers/dri/i965/brw_draw_upload.c b/src/mesa/drivers/dri/i965/brw_draw_upload.c index 1b8bcc14ec..3ef56a0068 100644 --- a/src/mesa/drivers/dri/i965/brw_draw_upload.c +++ b/src/mesa/drivers/dri/i965/brw_draw_upload.c @@ -635,7 +635,7 @@ static void brw_emit_indices(struct brw_context *brw) if (index_buffer == NULL) return; - ib_size = get_size(index_buffer->type) * index_buffer->count; + ib_size = get_size(index_buffer->type) * index_buffer->count - 1; /* Emit the indexbuffer packet: */ diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h index bc7756ceab..3ee56fe1b6 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.h +++ b/src/mesa/drivers/dri/i965/brw_eu.h @@ -855,12 +855,10 @@ void brw_math( struct brw_compile *p, void brw_dp_READ_16( struct brw_compile *p, struct brw_reg dest, - GLuint msg_reg_nr, GLuint scratch_offset ); void brw_dp_READ_4( struct brw_compile *p, struct brw_reg dest, - GLuint msg_reg_nr, GLboolean relAddr, GLuint location, GLuint bind_table_index ); @@ -875,7 +873,6 @@ void brw_dp_READ_4_vs( struct brw_compile *p, void brw_dp_WRITE_16( struct brw_compile *p, struct brw_reg src, - GLuint msg_reg_nr, GLuint scratch_offset ); /* If/else/endif. Works by manipulating the execution flags on each diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c index 60ea44f7a9..2a147fb8c3 100644 --- a/src/mesa/drivers/dri/i965/brw_eu_emit.c +++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c @@ -865,9 +865,9 @@ void brw_math_16( struct brw_compile *p, */ void brw_dp_WRITE_16( struct brw_compile *p, struct brw_reg src, - GLuint msg_reg_nr, GLuint scratch_offset ) { + GLuint msg_reg_nr = 1; { brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); @@ -877,7 +877,7 @@ void brw_dp_WRITE_16( struct brw_compile *p, brw_MOV(p, retype(brw_vec1_grf(0, 2), BRW_REGISTER_TYPE_D), brw_imm_d(scratch_offset)); - + brw_pop_insn_state(p); } @@ -912,9 +912,9 @@ void brw_dp_WRITE_16( struct brw_compile *p, */ void brw_dp_READ_16( struct brw_compile *p, struct brw_reg dest, - GLuint msg_reg_nr, GLuint scratch_offset ) { + GLuint msg_reg_nr = 1; { brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); @@ -924,7 +924,7 @@ void brw_dp_READ_16( struct brw_compile *p, brw_MOV(p, retype(brw_vec1_grf(0, 2), BRW_REGISTER_TYPE_D), brw_imm_d(scratch_offset)); - + brw_pop_insn_state(p); } @@ -958,21 +958,26 @@ void brw_dp_READ_16( struct brw_compile *p, */ void brw_dp_READ_4( struct brw_compile *p, struct brw_reg dest, - GLuint msg_reg_nr, GLboolean relAddr, GLuint location, GLuint bind_table_index ) { + /* XXX: relAddr not implemented */ + GLuint msg_reg_nr = 1; { + struct brw_reg b; brw_push_insn_state(p); + brw_set_predicate_control(p, BRW_PREDICATE_NONE); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_mask_control(p, BRW_MASK_DISABLE); - /* set message header global offset field (reg 0, element 2) */ - /* Note that grf[0] will be copied to mrf[1] implicitly by the SEND instr */ - brw_MOV(p, - retype(brw_vec1_grf(0, 2), BRW_REGISTER_TYPE_UD), - brw_imm_d(location)); + /* Setup MRF[1] with location/offset into const buffer */ + b = brw_message_reg(msg_reg_nr); + b = retype(b, BRW_REGISTER_TYPE_UD); + /* XXX I think we're setting all the dwords of MRF[1] to 'location'. + * when the docs say only dword[2] should be set. Hmmm. But it works. + */ + brw_MOV(p, b, brw_imm_ud(location)); brw_pop_insn_state(p); } @@ -988,7 +993,7 @@ void brw_dp_READ_4( struct brw_compile *p, dest = retype(vec8(dest), BRW_REGISTER_TYPE_UW); brw_set_dest(insn, dest); - brw_set_src0(insn, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW)); + brw_set_src0(insn, brw_null_reg()); brw_set_dp_read_message(insn, bind_table_index, diff --git a/src/mesa/drivers/dri/i965/brw_misc_state.c b/src/mesa/drivers/dri/i965/brw_misc_state.c index 4784254bc7..67c39e509c 100644 --- a/src/mesa/drivers/dri/i965/brw_misc_state.c +++ b/src/mesa/drivers/dri/i965/brw_misc_state.c @@ -244,6 +244,8 @@ static void emit_depthbuffer(struct brw_context *brw) return; } + assert(region->tiling != I915_TILING_X); + BEGIN_BATCH(len, IGNORE_CLIPRECTS); OUT_BATCH(CMD_DEPTH_BUFFER << 16 | (len - 2)); OUT_BATCH(((region->pitch * region->cpp) - 1) | diff --git a/src/mesa/drivers/dri/i965/brw_vtbl.c b/src/mesa/drivers/dri/i965/brw_vtbl.c index ba03afd6c1..b284e623d0 100644 --- a/src/mesa/drivers/dri/i965/brw_vtbl.c +++ b/src/mesa/drivers/dri/i965/brw_vtbl.c @@ -194,7 +194,7 @@ static GLuint brw_flush_cmd( void ) struct brw_mi_flush flush; flush.opcode = CMD_MI_FLUSH; flush.pad = 0; - flush.flags = BRW_FLUSH_READ_CACHE | BRW_FLUSH_STATE_CACHE; + flush.flags = BRW_FLUSH_STATE_CACHE; return *(GLuint *)&flush; } diff --git a/src/mesa/drivers/dri/i965/brw_wm_emit.c b/src/mesa/drivers/dri/i965/brw_wm_emit.c index 14ab9042de..4c3879f9fa 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_emit.c +++ b/src/mesa/drivers/dri/i965/brw_wm_emit.c @@ -1057,7 +1057,6 @@ static void emit_spill( struct brw_wm_compile *c, */ brw_dp_WRITE_16(p, retype(vec16(brw_vec8_grf(0, 0)), BRW_REGISTER_TYPE_UW), - 1, slot); } @@ -1085,7 +1084,6 @@ static void emit_unspill( struct brw_wm_compile *c, brw_dp_READ_16(p, retype(vec16(reg), BRW_REGISTER_TYPE_UW), - 1, slot); } diff --git a/src/mesa/drivers/dri/i965/brw_wm_glsl.c b/src/mesa/drivers/dri/i965/brw_wm_glsl.c index 6c071f121d..6e6f2bac7b 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_glsl.c +++ b/src/mesa/drivers/dri/i965/brw_wm_glsl.c @@ -446,7 +446,6 @@ static void fetch_constants(struct brw_wm_compile *c, /* need to fetch the constant now */ brw_dp_READ_4(p, c->current_const[i].reg, /* writeback dest */ - 1, /* msg_reg */ src->RelAddr, /* relative indexing? */ 16 * src->Index, /* byte offset */ SURF_INDEX_FRAG_CONST_BUFFER/* binding table index */ diff --git a/src/mesa/drivers/dri/i965/intel_pixel_read.c b/src/mesa/drivers/dri/i965/intel_pixel_read.c new file mode 120000 index 0000000000..cc4589f4d4 --- /dev/null +++ b/src/mesa/drivers/dri/i965/intel_pixel_read.c @@ -0,0 +1 @@ +../intel/intel_pixel_read.c
\ No newline at end of file diff --git a/src/mesa/drivers/dri/intel/intel_blit.c b/src/mesa/drivers/dri/intel/intel_blit.c index 4919828131..75d315d82b 100644 --- a/src/mesa/drivers/dri/intel/intel_blit.c +++ b/src/mesa/drivers/dri/intel/intel_blit.c @@ -108,6 +108,8 @@ intelCopyBuffer(const __DRIdrawablePrivate * dPriv, CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; } + assert(src->tiling != I915_TILING_Y); + assert(dst->tiling != I915_TILING_Y); #ifndef I915 if (src->tiling != I915_TILING_NONE) { CMD |= XY_SRC_TILED; @@ -175,66 +177,6 @@ intelCopyBuffer(const __DRIdrawablePrivate * dPriv, UNLOCK_HARDWARE(intel); } - - - -void -intelEmitFillBlit(struct intel_context *intel, - GLuint cpp, - GLshort dst_pitch, - dri_bo *dst_buffer, - GLuint dst_offset, - uint32_t dst_tiling, - GLshort x, GLshort y, - GLshort w, GLshort h, - GLuint color) -{ - GLuint BR13, CMD; - BATCH_LOCALS; - - dst_pitch *= cpp; - - switch (cpp) { - case 1: - BR13 = (0xF0 << 16); - CMD = XY_COLOR_BLT_CMD; - break; - case 2: - BR13 = (0xF0 << 16) | BR13_565; - CMD = XY_COLOR_BLT_CMD; - break; - case 4: - BR13 = (0xF0 << 16) | BR13_8888; - CMD = XY_COLOR_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; - break; - default: - return; - } -#ifndef I915 - if (dst_tiling != I915_TILING_NONE) { - CMD |= XY_DST_TILED; - dst_pitch /= 4; - } -#endif - - DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", - __FUNCTION__, dst_buffer, dst_pitch, dst_offset, x, y, w, h); - - assert(w > 0); - assert(h > 0); - - BEGIN_BATCH(6, NO_LOOP_CLIPRECTS); - OUT_BATCH(CMD); - OUT_BATCH(BR13 | dst_pitch); - OUT_BATCH((y << 16) | x); - OUT_BATCH(((y + h) << 16) | (x + w)); - OUT_RELOC(dst_buffer, - I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, - dst_offset); - OUT_BATCH(color); - ADVANCE_BATCH(); -} - static GLuint translate_raster_op(GLenum logicop) { switch(logicop) { @@ -261,7 +203,7 @@ static GLuint translate_raster_op(GLenum logicop) /* Copy BitBlt */ -void +GLboolean intelEmitCopyBlit(struct intel_context *intel, GLuint cpp, GLshort src_pitch, @@ -283,6 +225,19 @@ intelEmitCopyBlit(struct intel_context *intel, dri_bo *aper_array[3]; BATCH_LOCALS; + if (dst_tiling != I915_TILING_NONE) { + if (dst_offset & 4095) + return GL_FALSE; + if (dst_tiling == I915_TILING_Y) + return GL_FALSE; + } + if (src_tiling != I915_TILING_NONE) { + if (src_offset & 4095) + return GL_FALSE; + if (src_tiling == I915_TILING_Y) + return GL_FALSE; + } + /* do space/cliprects check before going any further */ do { aper_array[0] = intel->batch->buf; @@ -320,7 +275,7 @@ intelEmitCopyBlit(struct intel_context *intel, if (locked) UNLOCK_HARDWARE(intel); - return; + return GL_TRUE; } intel_batchbuffer_require_space(intel->batch, 8 * 4, NO_LOOP_CLIPRECTS); @@ -347,7 +302,7 @@ intelEmitCopyBlit(struct intel_context *intel, CMD = XY_SRC_COPY_BLT_CMD | XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; break; default: - return; + return GL_FALSE; } #ifndef I915 @@ -362,7 +317,7 @@ intelEmitCopyBlit(struct intel_context *intel, #endif if (dst_y2 <= dst_y || dst_x2 <= dst_x) { - return; + return GL_TRUE; } assert(dst_x < dst_x2); @@ -384,6 +339,8 @@ intelEmitCopyBlit(struct intel_context *intel, ADVANCE_BATCH(); intel_batchbuffer_emit_mi_flush(intel->batch); + + return GL_TRUE; } @@ -596,7 +553,7 @@ intelClearWithBlit(GLcontext *ctx, GLbitfield mask) UNLOCK_HARDWARE(intel); } -void +GLboolean intelEmitImmediateColorExpandBlit(struct intel_context *intel, GLuint cpp, GLubyte *src_bits, GLuint src_size, @@ -612,11 +569,18 @@ intelEmitImmediateColorExpandBlit(struct intel_context *intel, int dwords = ALIGN(src_size, 8) / 4; uint32_t opcode, br13, blit_cmd; + if (dst_tiling != I915_TILING_NONE) { + if (dst_offset & 4095) + return GL_FALSE; + if (dst_tiling == I915_TILING_Y) + return GL_FALSE; + } + assert( logic_op - GL_CLEAR >= 0 ); assert( logic_op - GL_CLEAR < 0x10 ); if (w < 0 || h < 0) - return; + return GL_TRUE; dst_pitch *= cpp; @@ -673,4 +637,6 @@ intelEmitImmediateColorExpandBlit(struct intel_context *intel, REFERENCES_CLIPRECTS ); intel_batchbuffer_emit_mi_flush(intel->batch); + + return GL_TRUE; } diff --git a/src/mesa/drivers/dri/intel/intel_blit.h b/src/mesa/drivers/dri/intel/intel_blit.h index 52065b13ed..152fa3f17b 100644 --- a/src/mesa/drivers/dri/intel/intel_blit.h +++ b/src/mesa/drivers/dri/intel/intel_blit.h @@ -35,7 +35,8 @@ extern void intelCopyBuffer(const __DRIdrawablePrivate * dpriv, extern void intelClearWithBlit(GLcontext * ctx, GLbitfield mask); -extern void intelEmitCopyBlit(struct intel_context *intel, +GLboolean +intelEmitCopyBlit(struct intel_context *intel, GLuint cpp, GLshort src_pitch, dri_bo *src_buffer, @@ -50,16 +51,7 @@ extern void intelEmitCopyBlit(struct intel_context *intel, GLshort w, GLshort h, GLenum logicop ); -extern void intelEmitFillBlit(struct intel_context *intel, - GLuint cpp, - GLshort dst_pitch, - dri_bo *dst_buffer, - GLuint dst_offset, - uint32_t dst_tiling, - GLshort x, GLshort y, - GLshort w, GLshort h, GLuint color); - -void +GLboolean intelEmitImmediateColorExpandBlit(struct intel_context *intel, GLuint cpp, GLubyte *src_bits, GLuint src_size, diff --git a/src/mesa/drivers/dri/intel/intel_buffer_objects.c b/src/mesa/drivers/dri/intel/intel_buffer_objects.c index 1f10dec0a4..aed0e45a28 100644 --- a/src/mesa/drivers/dri/intel/intel_buffer_objects.c +++ b/src/mesa/drivers/dri/intel/intel_buffer_objects.c @@ -300,14 +300,19 @@ intel_bufferobj_buffer(struct intel_context *intel, } if (intel_obj->buffer == NULL) { + void *sys_buffer = intel_obj->sys_buffer; + + /* only one of buffer and sys_buffer could be non-NULL */ intel_bufferobj_alloc_buffer(intel, intel_obj); + intel_obj->sys_buffer = NULL; + intel_bufferobj_subdata(&intel->ctx, GL_ARRAY_BUFFER_ARB, 0, intel_obj->Base.Size, - intel_obj->sys_buffer, + sys_buffer, &intel_obj->Base); - _mesa_free(intel_obj->sys_buffer); + _mesa_free(sys_buffer); intel_obj->sys_buffer = NULL; } diff --git a/src/mesa/drivers/dri/intel/intel_buffers.c b/src/mesa/drivers/dri/intel/intel_buffers.c index df5c3fc176..e7357e78c5 100644 --- a/src/mesa/drivers/dri/intel/intel_buffers.c +++ b/src/mesa/drivers/dri/intel/intel_buffers.c @@ -345,6 +345,23 @@ intelDrawBuffer(GLcontext * ctx, GLenum mode) static void intelReadBuffer(GLcontext * ctx, GLenum mode) { + if ((ctx->DrawBuffer != NULL) && (ctx->DrawBuffer->Name == 0)) { + struct intel_context *const intel = intel_context(ctx); + const GLboolean was_front_buffer_reading = + intel->is_front_buffer_reading; + + intel->is_front_buffer_reading = (mode == GL_FRONT_LEFT) + || (mode == GL_FRONT); + + /* If we weren't front-buffer reading before but we are now, make sure + * that the front-buffer has actually been allocated. + */ + if (!was_front_buffer_reading && intel->is_front_buffer_reading) { + intel_update_renderbuffers(intel->driContext, + intel->driContext->driDrawablePriv); + } + } + if (ctx->ReadBuffer == ctx->DrawBuffer) { /* This will update FBO completeness status. * A framebuffer will be incomplete if the GL_READ_BUFFER setting diff --git a/src/mesa/drivers/dri/intel/intel_clear.c b/src/mesa/drivers/dri/intel/intel_clear.c index 21f534d090..273856fd2f 100644 --- a/src/mesa/drivers/dri/intel/intel_clear.c +++ b/src/mesa/drivers/dri/intel/intel_clear.c @@ -264,7 +264,7 @@ intel_clear_tris(GLcontext *ctx, GLbitfield mask) _mesa_Disable(GL_STENCIL_TEST); } - CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); mask &= ~this_mask; } diff --git a/src/mesa/drivers/dri/intel/intel_context.c b/src/mesa/drivers/dri/intel/intel_context.c index 4138764604..21d13b862b 100644 --- a/src/mesa/drivers/dri/intel/intel_context.c +++ b/src/mesa/drivers/dri/intel/intel_context.c @@ -71,6 +71,8 @@ int INTEL_DEBUG = (0); #define DRIVER_DATE_GEM "GEM " DRIVER_DATE +static void intel_flush(GLcontext *ctx, GLboolean needs_mi_flush); + static const GLubyte * intelGetString(GLcontext * ctx, GLenum name) { @@ -218,7 +220,9 @@ intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) struct intel_renderbuffer *stencil_rb; i = 0; - if ((intel->is_front_buffer_rendering || !intel_fb->color_rb[1]) + if ((intel->is_front_buffer_rendering || + intel->is_front_buffer_reading || + !intel_fb->color_rb[1]) && intel_fb->color_rb[0]) { attachments[i++] = __DRI_BUFFER_FRONT_LEFT; attachments[i++] = intel_bits_per_pixel(intel_fb->color_rb[0]); @@ -395,6 +399,15 @@ intel_viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h) return; if (!intel->internal_viewport_call && ctx->DrawBuffer->Name == 0) { + /* If we're rendering to the fake front buffer, make sure all the pending + * drawing has landed on the real front buffer. Otherwise when we + * eventually get to DRI2GetBuffersWithFormat the stale real front + * buffer contents will get copied to the new fake front buffer. + */ + if (intel->is_front_buffer_rendering) { + intel_flush(ctx, GL_FALSE); + } + intel_update_renderbuffers(driContext, driContext->driDrawablePriv); if (driContext->driDrawablePriv != driContext->driReadablePriv) intel_update_renderbuffers(driContext, driContext->driReadablePriv); @@ -729,6 +742,12 @@ intelInitContext(struct intel_context *intel, } intel->use_texture_tiling = driQueryOptionb(&intel->optionCache, "texture_tiling"); + if (intel->use_texture_tiling && + !intel->intelScreen->kernel_exec_fencing) { + fprintf(stderr, "No kernel support for execution fencing, " + "disabling texture tiling"); + intel->use_texture_tiling = GL_FALSE; + } intel->use_early_z = driQueryOptionb(&intel->optionCache, "early_z"); intel->prim.primitive = ~0; diff --git a/src/mesa/drivers/dri/intel/intel_context.h b/src/mesa/drivers/dri/intel/intel_context.h index 7d3c80bb21..36f33b6f31 100644 --- a/src/mesa/drivers/dri/intel/intel_context.h +++ b/src/mesa/drivers/dri/intel/intel_context.h @@ -304,6 +304,14 @@ struct intel_context * easily. */ GLboolean is_front_buffer_rendering; + /** + * Track whether front-buffer is the current read target. + * + * This is closely associated with is_front_buffer_rendering, but may + * be set separately. The DRI2 fake front buffer must be referenced + * either way. + */ + GLboolean is_front_buffer_reading; GLboolean use_texture_tiling; GLboolean use_early_z; diff --git a/src/mesa/drivers/dri/intel/intel_generatemipmap.c b/src/mesa/drivers/dri/intel/intel_generatemipmap.c index 1060fbd9e5..b00f8019dd 100644 --- a/src/mesa/drivers/dri/intel/intel_generatemipmap.c +++ b/src/mesa/drivers/dri/intel/intel_generatemipmap.c @@ -106,7 +106,7 @@ intel_generate_mipmap_level(GLcontext *ctx, GLuint tex_name, _mesa_Enable(GL_VERTEX_ARRAY); intel_meta_set_default_texrect(intel); - CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c index fcfed9e751..a0d8f0c27a 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c @@ -101,6 +101,7 @@ intel_miptree_create_internal(struct intel_context *intel, struct intel_mipmap_tree * intel_miptree_create(struct intel_context *intel, GLenum target, + GLenum base_format, GLenum internal_format, GLuint first_level, GLuint last_level, @@ -115,7 +116,8 @@ intel_miptree_create(struct intel_context *intel, if (intel->use_texture_tiling && compress_byte == 0 && intel->intelScreen->kernel_exec_fencing) { if (IS_965(intel->intelScreen->deviceID) && - internal_format == GL_DEPTH_COMPONENT) + (base_format == GL_DEPTH_COMPONENT || + base_format == GL_DEPTH_STENCIL_EXT)) tiling = I915_TILING_Y; else tiling = I915_TILING_X; @@ -498,6 +500,7 @@ intel_miptree_image_copy(struct intel_context *intel, const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level); GLuint i; + GLboolean success; if (dst->compressed) { GLuint alignment = intel_compressed_alignment(dst->internal_format); @@ -506,12 +509,26 @@ intel_miptree_image_copy(struct intel_context *intel, } for (i = 0; i < depth; i++) { - intel_region_copy(intel, - dst->region, dst_offset + dst_depth_offset[i], - 0, - 0, - src->region, src_offset + src_depth_offset[i], - 0, 0, width, height); + success = intel_region_copy(intel, + dst->region, dst_offset + dst_depth_offset[i], + 0, 0, + src->region, src_offset + src_depth_offset[i], + 0, 0, width, height, GL_COPY); + if (!success) { + GLubyte *src_ptr, *dst_ptr; + + src_ptr = intel_region_map(intel, src->region); + dst_ptr = intel_region_map(intel, dst->region); + + _mesa_copy_rect(dst_ptr + dst_offset + dst_depth_offset[i], + dst->cpp, + dst->pitch, + 0, 0, width, height, + src_ptr + src_offset + src_depth_offset[i], + src->pitch, + 0, 0); + intel_region_unmap(intel, src->region); + intel_region_unmap(intel, dst->region); + } } - } diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h index 3af9966827..2a809cfda5 100644 --- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h +++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h @@ -126,6 +126,7 @@ struct intel_mipmap_tree struct intel_mipmap_tree *intel_miptree_create(struct intel_context *intel, GLenum target, + GLenum base_format, GLenum internal_format, GLuint first_level, GLuint last_level, diff --git a/src/mesa/drivers/dri/intel/intel_pixel.c b/src/mesa/drivers/dri/intel/intel_pixel.c index 36a684b3b8..da9ccb23f1 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel.c +++ b/src/mesa/drivers/dri/intel/intel_pixel.c @@ -424,10 +424,8 @@ intelInitPixelFuncs(struct dd_function_table *functions) functions->Bitmap = intelBitmap; functions->CopyPixels = intelCopyPixels; functions->DrawPixels = intelDrawPixels; -#ifdef I915 - functions->ReadPixels = intelReadPixels; -#endif } + functions->ReadPixels = intelReadPixels; } void diff --git a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c index 80d3239189..e678cd2c26 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c @@ -194,7 +194,7 @@ do_blit_bitmap( GLcontext *ctx, struct gl_framebuffer *fb = ctx->DrawBuffer; GLfloat tmpColor[4]; GLubyte ubcolor[4]; - GLuint color8888, color565; + GLuint color; unsigned int num_cliprects; drm_clip_rect_t *cliprects; int x_off, y_off; @@ -232,8 +232,11 @@ do_blit_bitmap( GLcontext *ctx, UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]); UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]); - color8888 = INTEL_PACKCOLOR8888(ubcolor[0], ubcolor[1], ubcolor[2], ubcolor[3]); - color565 = INTEL_PACKCOLOR565(ubcolor[0], ubcolor[1], ubcolor[2]); + if (dst->cpp == 2) + color = INTEL_PACKCOLOR565(ubcolor[0], ubcolor[1], ubcolor[2]); + else + color = INTEL_PACKCOLOR8888(ubcolor[0], ubcolor[1], + ubcolor[2], ubcolor[3]); if (!intel_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F)) return GL_FALSE; @@ -307,21 +310,21 @@ do_blit_bitmap( GLcontext *ctx, fb->Name == 0 ? GL_TRUE : GL_FALSE) == 0) continue; - /* - */ - intelEmitImmediateColorExpandBlit( intel, - dst->cpp, - (GLubyte *)stipple, - sz, - (dst->cpp == 2) ? color565 : color8888, - dst->pitch, - dst->buffer, - 0, - dst->tiling, - box_x + px, - box_y + py, - w, h, - logic_op); + if (!intelEmitImmediateColorExpandBlit(intel, + dst->cpp, + (GLubyte *)stipple, + sz, + color, + dst->pitch, + dst->buffer, + 0, + dst->tiling, + box_x + px, + box_y + py, + w, h, + logic_op)) { + return GL_FALSE; + } } } } @@ -495,7 +498,7 @@ intel_texture_bitmap(GLcontext * ctx, _mesa_VertexPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &vertices); _mesa_Enable(GL_VERTEX_ARRAY); intel_meta_set_default_texrect(intel); - CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); diff --git a/src/mesa/drivers/dri/intel/intel_pixel_copy.c b/src/mesa/drivers/dri/intel/intel_pixel_copy.c index d50dd68092..f523d3eead 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_copy.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_copy.c @@ -362,14 +362,16 @@ do_blit_copypixels(GLcontext * ctx, &clip_x, &clip_y, &clip_w, &clip_h)) continue; - intelEmitCopyBlit(intel, dst->cpp, - src->pitch, src->buffer, 0, src->tiling, - dst->pitch, dst->buffer, 0, dst->tiling, - clip_x + delta_x, clip_y + delta_y, /* srcx, srcy */ - clip_x, clip_y, /* dstx, dsty */ - clip_w, clip_h, - ctx->Color.ColorLogicOpEnabled ? - ctx->Color.LogicOp : GL_COPY); + if (!intel_region_copy(intel, + dst, 0, clip_x, clip_y, + src, 0, clip_x + delta_x, clip_y + delta_y, + clip_w, clip_h, + ctx->Color.ColorLogicOpEnabled ? + ctx->Color.LogicOp : GL_COPY)) { + DBG("%s: blit failure\n", __FUNCTION__); + UNLOCK_HARDWARE(intel); + return GL_FALSE; + } } } out: diff --git a/src/mesa/drivers/dri/intel/intel_pixel_draw.c b/src/mesa/drivers/dri/intel/intel_pixel_draw.c index 46d27f1a93..d79d625f77 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_draw.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_draw.c @@ -180,7 +180,7 @@ intel_texture_drawpixels(GLcontext * ctx, _mesa_Enable(GL_VERTEX_ARRAY); intel_meta_set_default_texrect(intel); - CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); @@ -361,7 +361,7 @@ intel_stencil_drawpixels(GLcontext * ctx, _mesa_Enable(GL_VERTEX_ARRAY); intel_meta_set_default_texrect(intel); - CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); intel_meta_restore_texcoords(intel); intel_meta_restore_transform(intel); diff --git a/src/mesa/drivers/dri/intel/intel_pixel_read.c b/src/mesa/drivers/dri/intel/intel_pixel_read.c new file mode 100644 index 0000000000..8713463ace --- /dev/null +++ b/src/mesa/drivers/dri/intel/intel_pixel_read.c @@ -0,0 +1,324 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * 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 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 TUNGSTEN GRAPHICS AND/OR ITS 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 "main/glheader.h" +#include "main/enums.h" +#include "main/mtypes.h" +#include "main/macros.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/state.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_buffers.h" +#include "intel_regions.h" +#include "intel_pixel.h" +#include "intel_buffer_objects.h" + +/* For many applications, the new ability to pull the source buffers + * back out of the GTT and then do the packing/conversion operations + * in software will be as much of an improvement as trying to get the + * blitter and/or texture engine to do the work. + * + * This step is gated on private backbuffers. + * + * Obviously the frontbuffer can't be pulled back, so that is either + * an argument for blit/texture readpixels, or for blitting to a + * temporary and then pulling that back. + * + * When the destination is a pbo, however, it's not clear if it is + * ever going to be pulled to main memory (though the access param + * will be a good hint). So it sounds like we do want to be able to + * choose between blit/texture implementation on the gpu and pullback + * and cpu-based copying. + * + * Unless you can magically turn client memory into a PBO for the + * duration of this call, there will be a cpu-based copying step in + * any case. + */ + + +static GLboolean +do_texture_readpixels(GLcontext * ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + struct intel_region *dest_region) +{ +#if 0 + struct intel_context *intel = intel_context(ctx); + intelScreenPrivate *screen = intel->intelScreen; + GLint pitch = pack->RowLength ? pack->RowLength : width; + __DRIdrawablePrivate *dPriv = intel->driDrawable; + int textureFormat; + GLenum glTextureFormat; + int destFormat, depthFormat, destPitch; + drm_clip_rect_t tmp; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + + if (ctx->_ImageTransferState || + pack->SwapBytes || pack->LsbFirst || !pack->Invert) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: check_color failed\n", __FUNCTION__); + return GL_FALSE; + } + + intel->vtbl.meta_texrect_source(intel, intel_readbuf_region(intel)); + + if (!intel->vtbl.meta_render_dest(intel, dest_region, type, format)) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: couldn't set dest %s/%s\n", + __FUNCTION__, + _mesa_lookup_enum_by_nr(type), + _mesa_lookup_enum_by_nr(format)); + return GL_FALSE; + } + + LOCK_HARDWARE(intel); + + if (intel->driDrawable->numClipRects) { + intel->vtbl.install_meta_state(intel); + intel->vtbl.meta_no_depth_write(intel); + intel->vtbl.meta_no_stencil_write(intel); + + if (!driClipRectToFramebuffer(ctx->ReadBuffer, &x, &y, &width, &height)) { + UNLOCK_HARDWARE(intel); + SET_STATE(i830, state); + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: cliprect failed\n", __FUNCTION__); + return GL_TRUE; + } + + y = dPriv->h - y - height; + x += dPriv->x; + y += dPriv->y; + + + /* Set the frontbuffer up as a large rectangular texture. + */ + intel->vtbl.meta_tex_rect_source(intel, src_region, textureFormat); + + + intel->vtbl.meta_texture_blend_replace(i830, glTextureFormat); + + + /* Set the 3d engine to draw into the destination region: + */ + + intel->vtbl.meta_draw_region(intel, dest_region); + intel->vtbl.meta_draw_format(intel, destFormat, depthFormat); /* ?? */ + + + /* Draw a single quad, no cliprects: + */ + intel->vtbl.meta_disable_cliprects(intel); + + intel->vtbl.draw_quad(intel, + 0, width, 0, height, + 0x00ff00ff, x, x + width, y, y + height); + + intel->vtbl.leave_meta_state(intel); + } + UNLOCK_HARDWARE(intel); + + intel_region_wait_fence(ctx, dest_region); /* required by GL */ + return GL_TRUE; +#endif + + return GL_FALSE; +} + + + + +static GLboolean +do_blit_readpixels(GLcontext * ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, GLvoid * pixels) +{ + struct intel_context *intel = intel_context(ctx); + struct intel_region *src = intel_readbuf_region(intel); + struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj); + GLuint dst_offset; + GLuint rowLength; + + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s\n", __FUNCTION__); + + if (!src) + return GL_FALSE; + + if (pack->BufferObj->Name) { + /* XXX This validation should be done by core mesa: + */ + if (!_mesa_validate_pbo_access(2, pack, width, height, 1, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); + return GL_TRUE; + } + } + else { + /* PBO only for now: + */ + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s - not PBO\n", __FUNCTION__); + return GL_FALSE; + } + + + if (ctx->_ImageTransferState || + !intel_check_blit_format(src, format, type)) { + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s - bad format for blit\n", __FUNCTION__); + return GL_FALSE; + } + + if (pack->Alignment != 1 || pack->SwapBytes || pack->LsbFirst) { + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s: bad packing params\n", __FUNCTION__); + return GL_FALSE; + } + + if (pack->RowLength > 0) + rowLength = pack->RowLength; + else + rowLength = width; + + if (pack->Invert) { + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s: MESA_PACK_INVERT not done yet\n", __FUNCTION__); + return GL_FALSE; + } + else { + rowLength = -rowLength; + } + + /* XXX 64-bit cast? */ + dst_offset = (GLuint) _mesa_image_address(2, pack, pixels, width, height, + format, type, 0, 0, 0); + + + /* Although the blits go on the command buffer, need to do this and + * fire with lock held to guarentee cliprects are correct. + */ + intelFlush(&intel->ctx); + LOCK_HARDWARE(intel); + + if (intel->driDrawable->numClipRects) { + GLboolean all = (width * height * src->cpp == dst->Base.Size && + x == 0 && dst_offset == 0); + + dri_bo *dst_buffer = intel_bufferobj_buffer(intel, dst, + all ? INTEL_WRITE_FULL : + INTEL_WRITE_PART); + __DRIdrawablePrivate *dPriv = intel->driDrawable; + int nbox = dPriv->numClipRects; + drm_clip_rect_t *box = dPriv->pClipRects; + drm_clip_rect_t rect; + drm_clip_rect_t src_rect; + int i; + + src_rect.x1 = dPriv->x + x; + src_rect.y1 = dPriv->y + dPriv->h - (y + height); + src_rect.x2 = src_rect.x1 + width; + src_rect.y2 = src_rect.y1 + height; + + + + for (i = 0; i < nbox; i++) { + if (!intel_intersect_cliprects(&rect, &src_rect, &box[i])) + continue; + + if (!intelEmitCopyBlit(intel, + src->cpp, + src->pitch, src->buffer, 0, src->tiling, + rowLength, dst_buffer, dst_offset, GL_FALSE, + rect.x1, + rect.y1, + rect.x1 - src_rect.x1, + rect.y2 - src_rect.y2, + rect.x2 - rect.x1, rect.y2 - rect.y1, + GL_COPY)) { + UNLOCK_HARDWARE(intel); + return GL_FALSE; + } + } + } + UNLOCK_HARDWARE(intel); + + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s - DONE\n", __FUNCTION__); + + return GL_TRUE; +} + +void +intelReadPixels(GLcontext * ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, GLvoid * pixels) +{ + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + intelFlush(ctx); + +#ifdef I915 + if (do_blit_readpixels + (ctx, x, y, width, height, format, type, pack, pixels)) + return; + + if (do_texture_readpixels + (ctx, x, y, width, height, format, type, pack, pixels)) + return; +#else + (void)do_blit_readpixels; + (void)do_texture_readpixels; +#endif + + if (INTEL_DEBUG & DEBUG_PIXEL) + _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); + + /* Update Mesa state before calling down into _swrast_ReadPixels, as + * the spans code requires the computed buffer states to be up to date, + * but _swrast_ReadPixels only updates Mesa state after setting up + * the spans code. + */ + + if (ctx->NewState) + _mesa_update_state(ctx); + + _swrast_ReadPixels(ctx, x, y, width, height, format, type, pack, pixels); +} diff --git a/src/mesa/drivers/dri/intel/intel_regions.c b/src/mesa/drivers/dri/intel/intel_regions.c index 7c3b483836..4ce7f12e40 100644 --- a/src/mesa/drivers/dri/intel/intel_regions.c +++ b/src/mesa/drivers/dri/intel/intel_regions.c @@ -116,7 +116,8 @@ intel_region_map(struct intel_context *intel, struct intel_region *region) if (region->pbo) intel_region_cow(intel, region); - if (intel->intelScreen->kernel_exec_fencing) + if (region->tiling != I915_TILING_NONE && + intel->intelScreen->kernel_exec_fencing) drm_intel_gem_bo_map_gtt(region->buffer); else dri_bo_map(region->buffer, GL_TRUE); @@ -131,7 +132,8 @@ intel_region_unmap(struct intel_context *intel, struct intel_region *region) { _DBG("%s %p\n", __FUNCTION__, region); if (!--region->map_refcount) { - if (intel->intelScreen->kernel_exec_fencing) + if (region->tiling != I915_TILING_NONE && + intel->intelScreen->kernel_exec_fencing) drm_intel_gem_bo_unmap_gtt(region->buffer); else dri_bo_unmap(region->buffer); @@ -358,19 +360,20 @@ intel_region_data(struct intel_context *intel, /* Copy rectangular sub-regions. Need better logic about when to * push buffers into AGP - will currently do so whenever possible. */ -void +GLboolean intel_region_copy(struct intel_context *intel, struct intel_region *dst, GLuint dst_offset, GLuint dstx, GLuint dsty, struct intel_region *src, GLuint src_offset, - GLuint srcx, GLuint srcy, GLuint width, GLuint height) + GLuint srcx, GLuint srcy, GLuint width, GLuint height, + GLenum logicop) { _DBG("%s\n", __FUNCTION__); if (intel == NULL) - return; + return GL_FALSE; if (dst->pbo) { if (dstx == 0 && @@ -382,41 +385,12 @@ intel_region_copy(struct intel_context *intel, assert(src->cpp == dst->cpp); - intelEmitCopyBlit(intel, - dst->cpp, - src->pitch, src->buffer, src_offset, src->tiling, - dst->pitch, dst->buffer, dst_offset, dst->tiling, - srcx, srcy, dstx, dsty, width, height, - GL_COPY); -} - -/* Fill a rectangular sub-region. Need better logic about when to - * push buffers into AGP - will currently do so whenever possible. - */ -void -intel_region_fill(struct intel_context *intel, - struct intel_region *dst, - GLuint dst_offset, - GLuint dstx, GLuint dsty, - GLuint width, GLuint height, GLuint color) -{ - _DBG("%s\n", __FUNCTION__); - - if (intel == NULL) - return; - - if (dst->pbo) { - if (dstx == 0 && - dsty == 0 && width == dst->pitch && height == dst->height) - intel_region_release_pbo(intel, dst); - else - intel_region_cow(intel, dst); - } - - intelEmitFillBlit(intel, - dst->cpp, - dst->pitch, dst->buffer, dst_offset, dst->tiling, - dstx, dsty, width, height, color); + return intelEmitCopyBlit(intel, + dst->cpp, + src->pitch, src->buffer, src_offset, src->tiling, + dst->pitch, dst->buffer, dst_offset, dst->tiling, + srcx, srcy, dstx, dsty, width, height, + logicop); } /* Attach to a pbo, discarding our data. Effectively zero-copy upload @@ -427,6 +401,8 @@ intel_region_attach_pbo(struct intel_context *intel, struct intel_region *region, struct intel_buffer_object *pbo) { + dri_bo *buffer; + if (region->pbo == pbo) return; @@ -447,10 +423,13 @@ intel_region_attach_pbo(struct intel_context *intel, region->buffer = NULL; } + /* make sure pbo has a buffer of its own */ + buffer = intel_bufferobj_buffer(intel, pbo, INTEL_WRITE_FULL); + region->pbo = pbo; region->pbo->region = region; - dri_bo_reference(pbo->buffer); - region->buffer = pbo->buffer; + dri_bo_reference(buffer); + region->buffer = buffer; } @@ -498,13 +477,13 @@ intel_region_cow(struct intel_context *intel, struct intel_region *region) if (!was_locked) LOCK_HARDWARE(intel); - intelEmitCopyBlit(intel, - region->cpp, - region->pitch, region->buffer, 0, region->tiling, - region->pitch, pbo->buffer, 0, region->tiling, - 0, 0, 0, 0, - region->pitch, region->height, - GL_COPY); + assert(intelEmitCopyBlit(intel, + region->cpp, + region->pitch, pbo->buffer, 0, region->tiling, + region->pitch, region->buffer, 0, region->tiling, + 0, 0, 0, 0, + region->pitch, region->height, + GL_COPY)); if (!was_locked) UNLOCK_HARDWARE(intel); diff --git a/src/mesa/drivers/dri/intel/intel_regions.h b/src/mesa/drivers/dri/intel/intel_regions.h index bd3c8e7325..0d379bdc6e 100644 --- a/src/mesa/drivers/dri/intel/intel_regions.h +++ b/src/mesa/drivers/dri/intel/intel_regions.h @@ -110,21 +110,15 @@ void intel_region_data(struct intel_context *intel, /* Copy rectangular sub-regions */ -void intel_region_copy(struct intel_context *intel, - struct intel_region *dest, - GLuint dest_offset, - GLuint destx, GLuint desty, - struct intel_region *src, - GLuint src_offset, - GLuint srcx, GLuint srcy, GLuint width, GLuint height); - -/* Fill a rectangular sub-region - */ -void intel_region_fill(struct intel_context *intel, - struct intel_region *dest, - GLuint dest_offset, - GLuint destx, GLuint desty, - GLuint width, GLuint height, GLuint color); +GLboolean +intel_region_copy(struct intel_context *intel, + struct intel_region *dest, + GLuint dest_offset, + GLuint destx, GLuint desty, + struct intel_region *src, + GLuint src_offset, + GLuint srcx, GLuint srcy, GLuint width, GLuint height, + GLenum logicop); /* Helpers for zerocopy uploads, particularly texture image uploads: */ diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c index 70e0980ed6..5b3fa9ead3 100644 --- a/src/mesa/drivers/dri/intel/intel_screen.c +++ b/src/mesa/drivers/dri/intel/intel_screen.c @@ -69,11 +69,7 @@ PUBLIC const char __driConfigOptions[] = DRI_CONF_DESC_END DRI_CONF_OPT_END -#ifdef I915 - DRI_CONF_TEXTURE_TILING(false) -#else - DRI_CONF_TEXTURE_TILING(true) -#endif + DRI_CONF_TEXTURE_TILING(false) DRI_CONF_OPT_BEGIN(early_z, bool, false) DRI_CONF_DESC(en, "Enable early Z in classic mode (unstable, 945-only).") diff --git a/src/mesa/drivers/dri/intel/intel_tex_copy.c b/src/mesa/drivers/dri/intel/intel_tex_copy.c index 260235b1eb..0335c13307 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_copy.c +++ b/src/mesa/drivers/dri/intel/intel_tex_copy.c @@ -107,6 +107,9 @@ do_copy_texsubimage(struct intel_context *intel, intelFlush(ctx); LOCK_HARDWARE(intel); { + drm_intel_bo *dst_bo = intel_region_buffer(intel, + intelImage->mt->region, + INTEL_WRITE_PART); GLuint image_offset = intel_miptree_image_offset(intelImage->mt, intelImage->face, intelImage->level); @@ -144,18 +147,21 @@ do_copy_texsubimage(struct intel_context *intel, src_pitch = src->pitch; } - intelEmitCopyBlit(intel, - intelImage->mt->cpp, - src_pitch, - src->buffer, - 0, - src->tiling, - intelImage->mt->pitch, - intelImage->mt->region->buffer, - image_offset, - intelImage->mt->region->tiling, - x, y, dstx, dsty, width, height, - GL_COPY); + if (!intelEmitCopyBlit(intel, + intelImage->mt->cpp, + src_pitch, + src->buffer, + 0, + src->tiling, + intelImage->mt->pitch, + dst_bo, + image_offset, + intelImage->mt->region->tiling, + x, y, dstx, dsty, width, height, + GL_COPY)) { + UNLOCK_HARDWARE(intel); + return GL_FALSE; + } } UNLOCK_HARDWARE(intel); diff --git a/src/mesa/drivers/dri/intel/intel_tex_image.c b/src/mesa/drivers/dri/intel/intel_tex_image.c index e9a3823078..c5f5220837 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_image.c +++ b/src/mesa/drivers/dri/intel/intel_tex_image.c @@ -131,6 +131,7 @@ guess_and_alloc_mipmap_tree(struct intel_context *intel, comp_byte = intel_compressed_num_bytes(intelImage->base.TexFormat->MesaFormat); intelObj->mt = intel_miptree_create(intel, intelObj->base.Target, + intelImage->base._BaseFormat, intelImage->base.InternalFormat, firstLevel, lastLevel, @@ -205,7 +206,7 @@ try_pbo_upload(struct intel_context *intel, GLuint src_offset, src_stride; GLuint dst_offset, dst_stride; - if (!pbo || + if (unpack->BufferObj->Name == 0 || intel->ctx._ImageTransferState || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: failure 1\n", __FUNCTION__); @@ -235,12 +236,15 @@ try_pbo_upload(struct intel_context *intel, INTEL_WRITE_FULL); - intelEmitCopyBlit(intel, - intelImage->mt->cpp, - src_stride, src_buffer, src_offset, GL_FALSE, - dst_stride, dst_buffer, dst_offset, GL_FALSE, - 0, 0, 0, 0, width, height, - GL_COPY); + if (!intelEmitCopyBlit(intel, + intelImage->mt->cpp, + src_stride, src_buffer, src_offset, GL_FALSE, + dst_stride, dst_buffer, dst_offset, GL_FALSE, + 0, 0, 0, 0, width, height, + GL_COPY)) { + UNLOCK_HARDWARE(intel); + return GL_FALSE; + } } UNLOCK_HARDWARE(intel); @@ -260,7 +264,7 @@ try_pbo_zcopy(struct intel_context *intel, GLuint src_offset, src_stride; GLuint dst_offset, dst_stride; - if (!pbo || + if (unpack->BufferObj->Name == 0 || intel->ctx._ImageTransferState || unpack->SkipPixels || unpack->SkipRows) { DBG("%s: failure 1\n", __FUNCTION__); @@ -409,7 +413,9 @@ intelTexImage(GLcontext * ctx, * a miptree, so create one just for our level and store it in the image. * It'll get moved into the object miptree at validate time. */ - intelImage->mt = intel_miptree_create(intel, target, internalFormat, + intelImage->mt = intel_miptree_create(intel, target, + intelImage->base.TexFormat->BaseFormat, + internalFormat, level, level, width, height, depth, intelImage->base.TexFormat->TexelBytes, @@ -421,7 +427,7 @@ intelTexImage(GLcontext * ctx, */ if (dims <= 2 && intelImage->mt && - intel_buffer_object(unpack->BufferObj) && + unpack->BufferObj->Name != 0 && check_pbo_format(internalFormat, format, type, intelImage->base.TexFormat)) { diff --git a/src/mesa/drivers/dri/intel/intel_tex_validate.c b/src/mesa/drivers/dri/intel/intel_tex_validate.c index b5cb7597d1..a284d5475f 100644 --- a/src/mesa/drivers/dri/intel/intel_tex_validate.c +++ b/src/mesa/drivers/dri/intel/intel_tex_validate.c @@ -199,6 +199,7 @@ intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) if (!intelObj->mt) { intelObj->mt = intel_miptree_create(intel, intelObj->base.Target, + firstImage->base._BaseFormat, firstImage->base.InternalFormat, intelObj->firstLevel, intelObj->lastLevel, diff --git a/src/mesa/drivers/dri/r200/r200_cmdbuf.c b/src/mesa/drivers/dri/r200/r200_cmdbuf.c index df9dd83344..fe173b601a 100644 --- a/src/mesa/drivers/dri/r200/r200_cmdbuf.c +++ b/src/mesa/drivers/dri/r200/r200_cmdbuf.c @@ -213,6 +213,9 @@ void r200FlushElts(GLcontext *ctx) radeon_bo_unref(rmesa->radeon.tcl.elt_dma_bo); rmesa->radeon.tcl.elt_dma_bo = NULL; + if (R200_ELT_BUF_SZ > elt_used) + radeonReturnDmaRegion(rmesa, R200_ELT_BUF_SZ - elt_used); + if (R200_DEBUG & DEBUG_SYNC) { fprintf(stderr, "%s: Syncing\n", __FUNCTION__); radeonFinish( rmesa->radeon.glCtx ); @@ -233,21 +236,13 @@ GLushort *r200AllocEltsOpenEnded( r200ContextPtr rmesa, radeonEmitState(&rmesa->radeon); - rmesa->radeon.tcl.elt_dma_bo = radeon_bo_open(rmesa->radeon.radeonScreen->bom, - 0, R200_ELT_BUF_SZ, 4, - RADEON_GEM_DOMAIN_GTT, 0); - rmesa->radeon.tcl.elt_dma_offset = 0; + radeonAllocDmaRegion(&rmesa->radeon, &rmesa->radeon.tcl.elt_dma_bo, + &rmesa->radeon.tcl.elt_dma_offset, R200_ELT_BUF_SZ, 4); rmesa->tcl.elt_used = min_nr * 2; - radeon_validate_bo(&rmesa->radeon, rmesa->radeon.tcl.elt_dma_bo, - RADEON_GEM_DOMAIN_GTT, 0); - if (radeon_revalidate_bos(rmesa->radeon.glCtx) == GL_FALSE) - fprintf(stderr,"failure to revalidate BOs - badness\n"); - radeon_bo_map(rmesa->radeon.tcl.elt_dma_bo, 1); retval = rmesa->radeon.tcl.elt_dma_bo->ptr + rmesa->radeon.tcl.elt_dma_offset; - if (R200_DEBUG & DEBUG_PRIMS) fprintf(stderr, "%s: header prim %x \n", __FUNCTION__, primitive); diff --git a/src/mesa/drivers/dri/r200/r200_context.c b/src/mesa/drivers/dri/r200/r200_context.c index 241390cef7..9a92a32079 100644 --- a/src/mesa/drivers/dri/r200/r200_context.c +++ b/src/mesa/drivers/dri/r200/r200_context.c @@ -357,6 +357,9 @@ GLboolean r200CreateContext( const __GLcontextModes *glVisual, /* FIXME: When no memory manager is available we should set this * to some reasonable value based on texture memory pool size */ ctx->Const.MaxTextureLevels = 12; + ctx->Const.Max3DTextureLevels = 9; + ctx->Const.MaxCubeTextureLevels = 12; + ctx->Const.MaxTextureRectSize = 2048; ctx->Const.MaxTextureMaxAnisotropy = 16.0; diff --git a/src/mesa/drivers/dri/r200/r200_ioctl.c b/src/mesa/drivers/dri/r200/r200_ioctl.c index 0b3398a730..6560efdca3 100644 --- a/src/mesa/drivers/dri/r200/r200_ioctl.c +++ b/src/mesa/drivers/dri/r200/r200_ioctl.c @@ -196,7 +196,10 @@ static void r200Clear( GLcontext *ctx, GLbitfield mask ) GLuint orig_mask = mask; if ( R200_DEBUG & DEBUG_IOCTL ) { - fprintf( stderr, "r200Clear %x %d\n", mask, rmesa->radeon.sarea->pfCurrentPage); + if (rmesa->radeon.sarea) + fprintf( stderr, "r200Clear %x %d\n", mask, rmesa->radeon.sarea->pfCurrentPage); + else + fprintf( stderr, "r200Clear %x radeon->sarea is NULL\n", mask); } { diff --git a/src/mesa/drivers/dri/r200/r200_state_init.c b/src/mesa/drivers/dri/r200/r200_state_init.c index f88ec877c5..c7df4b2587 100644 --- a/src/mesa/drivers/dri/r200/r200_state_init.c +++ b/src/mesa/drivers/dri/r200/r200_state_init.c @@ -585,6 +585,8 @@ static void tex_emit_cs(GLcontext *ctx, struct radeon_state_atom *atom) radeon_mipmap_level *lvl; int hastexture = 1; + if (!r200->state.texture.unit[i].unitneeded) + hastexture = 0; if (!t) hastexture = 0; else { diff --git a/src/mesa/drivers/dri/r300/r300_context.c b/src/mesa/drivers/dri/r300/r300_context.c index 7aa8075aa7..b7d75426c5 100644 --- a/src/mesa/drivers/dri/r300/r300_context.c +++ b/src/mesa/drivers/dri/r300/r300_context.c @@ -270,10 +270,16 @@ static void r300InitConstValues(GLcontext *ctx, radeonScreenPtr screen) ctx->Const.MaxTextureMaxAnisotropy = 16.0; ctx->Const.MaxTextureLodBias = 16.0; - if (screen->chip_family >= CHIP_FAMILY_RV515) + if (screen->chip_family >= CHIP_FAMILY_RV515) { ctx->Const.MaxTextureLevels = 13; - else + ctx->Const.MaxCubeTextureLevels = 13; + ctx->Const.MaxTextureRectSize = 4096; + } + else { ctx->Const.MaxTextureLevels = 12; + ctx->Const.MaxCubeTextureLevels = 12; + ctx->Const.MaxTextureRectSize = 2048; + } ctx->Const.MinPointSize = 1.0; ctx->Const.MinPointSizeAA = 1.0; @@ -412,6 +418,8 @@ GLboolean r300CreateContext(const __GLcontextModes * glVisual, _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); + _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); + /* Initialize the software rasterizer and helper modules. */ _swrast_CreateContext(ctx); diff --git a/src/mesa/drivers/dri/radeon/radeon_context.c b/src/mesa/drivers/dri/radeon/radeon_context.c index 229b4387ca..46cba73e29 100644 --- a/src/mesa/drivers/dri/radeon/radeon_context.c +++ b/src/mesa/drivers/dri/radeon/radeon_context.c @@ -285,8 +285,10 @@ r100CreateContext( const __GLcontextModes *glVisual, /* FIXME: When no memory manager is available we should set this * to some reasonable value based on texture memory pool size */ - /* FIXME: does r100 support 2048x2048 texture ? */ ctx->Const.MaxTextureLevels = 12; + ctx->Const.Max3DTextureLevels = 9; + ctx->Const.MaxCubeTextureLevels = 12; + ctx->Const.MaxTextureRectSize = 2048; ctx->Const.MaxTextureMaxAnisotropy = 16.0; diff --git a/src/mesa/drivers/dri/radeon/radeon_cs_legacy.c b/src/mesa/drivers/dri/radeon/radeon_cs_legacy.c index e4ee2b9915..ac94789417 100644 --- a/src/mesa/drivers/dri/radeon/radeon_cs_legacy.c +++ b/src/mesa/drivers/dri/radeon/radeon_cs_legacy.c @@ -391,11 +391,15 @@ static int cs_check_space(struct radeon_cs *cs, struct radeon_cs_space_check *bo continue; /* already accounted this bo */ - if (write_domain && (write_domain == bo->space_accounted)) + if (write_domain && (write_domain == bo->space_accounted)) { + bos[i].new_accounted = bo->space_accounted; continue; + } - if (read_domains && ((read_domains << 16) == bo->space_accounted)) + if (read_domains && ((read_domains << 16) == bo->space_accounted)) { + bos[i].new_accounted = bo->space_accounted; continue; + } if (bo->space_accounted == 0) { if (write_domain == RADEON_GEM_DOMAIN_VRAM) diff --git a/src/mesa/drivers/dri/radeon/radeon_dma.c b/src/mesa/drivers/dri/radeon/radeon_dma.c index 48b0d63818..0b91434b2b 100644 --- a/src/mesa/drivers/dri/radeon/radeon_dma.c +++ b/src/mesa/drivers/dri/radeon/radeon_dma.c @@ -167,7 +167,7 @@ void radeonRefillCurrentDmaRegion(radeonContextPtr rmesa, int size) size = MAX2(size, MAX_DMA_BUF_SZ); if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA)) - fprintf(stderr, "%s\n", __FUNCTION__); + fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->dma.nr_released_bufs); if (rmesa->dma.flush) { rmesa->dma.flush(rmesa->glCtx); @@ -178,11 +178,7 @@ void radeonRefillCurrentDmaRegion(radeonContextPtr rmesa, int size) rmesa->dma.nr_released_bufs = 0; } - if (rmesa->dma.current) { - radeon_bo_unmap(rmesa->dma.current); - radeon_bo_unref(rmesa->dma.current); - rmesa->dma.current = 0; - } + radeonReleaseDmaRegion(rmesa); again_alloc: rmesa->dma.current = radeon_bo_open(rmesa->radeonScreen->bom, @@ -244,6 +240,17 @@ void radeonAllocDmaRegion(radeonContextPtr rmesa, assert(rmesa->dma.current_used <= rmesa->dma.current->size); } +void radeonReturnDmaRegion(radeonContextPtr rmesa, int return_bytes) +{ + if (!rmesa->dma.current) + return; + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s %d\n", __FUNCTION__, return_bytes); + rmesa->dma.current_used -= return_bytes; + rmesa->dma.current_vertexptr = rmesa->dma.current_used; +} + void radeonReleaseDmaRegion(radeonContextPtr rmesa) { if (RADEON_DEBUG & DEBUG_IOCTL) diff --git a/src/mesa/drivers/dri/radeon/radeon_dma.h b/src/mesa/drivers/dri/radeon/radeon_dma.h index 06e388fc1d..c6eabd3bc8 100644 --- a/src/mesa/drivers/dri/radeon/radeon_dma.h +++ b/src/mesa/drivers/dri/radeon/radeon_dma.h @@ -39,6 +39,7 @@ void radeonEmitVec12(uint32_t *out, GLvoid * data, int stride, int count); void rcommon_emit_vector(GLcontext * ctx, struct radeon_aos *aos, GLvoid * data, int size, int stride, int count); +void radeonReturnDmaRegion(radeonContextPtr rmesa, int return_bytes); void radeonRefillCurrentDmaRegion(radeonContextPtr rmesa, int size); void radeonAllocDmaRegion(radeonContextPtr rmesa, struct radeon_bo **pbo, int *poffset, diff --git a/src/mesa/drivers/dri/radeon/radeon_texture.c b/src/mesa/drivers/dri/radeon/radeon_texture.c index 429ad50a7d..7dfed2c456 100644 --- a/src/mesa/drivers/dri/radeon/radeon_texture.c +++ b/src/mesa/drivers/dri/radeon/radeon_texture.c @@ -512,7 +512,7 @@ const struct gl_texture_format *radeonChooseTextureFormat(GLcontext * ctx, */ static void radeon_teximage( GLcontext *ctx, int dims, - GLint face, GLint level, + GLenum target, GLint level, GLint internalFormat, GLint width, GLint height, GLint depth, GLsizei imageSize, @@ -529,6 +529,7 @@ static void radeon_teximage( GLint postConvWidth = width; GLint postConvHeight = height; GLuint texelBytes; + GLuint face = radeon_face_for_target(target); radeon_firevertices(rmesa); @@ -653,7 +654,7 @@ static void radeon_teximage( /* SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { - radeon_generate_mipmap(ctx, texObj->Target, texObj); + radeon_generate_mipmap(ctx, target, texObj); } } @@ -673,7 +674,7 @@ void radeonTexImage1D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - radeon_teximage(ctx, 1, 0, level, internalFormat, width, 1, 1, + radeon_teximage(ctx, 1, target, level, internalFormat, width, 1, 1, 0, format, type, pixels, packing, texObj, texImage, 0); } @@ -686,9 +687,7 @@ void radeonTexImage2D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_image *texImage) { - GLuint face = radeon_face_for_target(target); - - radeon_teximage(ctx, 2, face, level, internalFormat, width, height, 1, + radeon_teximage(ctx, 2, target, level, internalFormat, width, height, 1, 0, format, type, pixels, packing, texObj, texImage, 0); } @@ -699,9 +698,7 @@ void radeonCompressedTexImage2D(GLcontext * ctx, GLenum target, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - GLuint face = radeon_face_for_target(target); - - radeon_teximage(ctx, 2, face, level, internalFormat, width, height, 1, + radeon_teximage(ctx, 2, target, level, internalFormat, width, height, 1, imageSize, 0, 0, data, &ctx->Unpack, texObj, texImage, 1); } @@ -714,14 +711,14 @@ void radeonTexImage3D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - radeon_teximage(ctx, 3, 0, level, internalFormat, width, height, depth, + radeon_teximage(ctx, 3, target, level, internalFormat, width, height, depth, 0, format, type, pixels, packing, texObj, texImage, 0); } /** * Update a subregion of the given texture image. */ -static void radeon_texsubimage(GLcontext* ctx, int dims, int level, +static void radeon_texsubimage(GLcontext* ctx, int dims, GLenum target, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, @@ -781,7 +778,7 @@ static void radeon_texsubimage(GLcontext* ctx, int dims, int level, /* GL_SGIS_generate_mipmap */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { - radeon_generate_mipmap(ctx, texObj->Target, texObj); + radeon_generate_mipmap(ctx, target, texObj); } } @@ -801,7 +798,7 @@ void radeonTexSubImage1D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - radeon_texsubimage(ctx, 1, level, xoffset, 0, 0, width, 1, 1, 0, + radeon_texsubimage(ctx, 1, target, level, xoffset, 0, 0, width, 1, 1, 0, format, type, pixels, packing, texObj, texImage, 0); } @@ -814,7 +811,7 @@ void radeonTexSubImage2D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - radeon_texsubimage(ctx, 2, level, xoffset, yoffset, 0, width, height, 1, + radeon_texsubimage(ctx, 2, target, level, xoffset, yoffset, 0, width, height, 1, 0, format, type, pixels, packing, texObj, texImage, 0); } @@ -827,7 +824,7 @@ void radeonCompressedTexSubImage2D(GLcontext * ctx, GLenum target, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - radeon_texsubimage(ctx, 2, level, xoffset, yoffset, 0, width, height, 1, + radeon_texsubimage(ctx, 2, target, level, xoffset, yoffset, 0, width, height, 1, imageSize, format, 0, data, &ctx->Unpack, texObj, texImage, 1); } @@ -841,7 +838,7 @@ void radeonTexSubImage3D(GLcontext * ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - radeon_texsubimage(ctx, 3, level, xoffset, yoffset, zoffset, width, height, depth, 0, + radeon_texsubimage(ctx, 3, target, level, xoffset, yoffset, zoffset, width, height, depth, 0, format, type, pixels, packing, texObj, texImage, 0); } diff --git a/src/mesa/drivers/x11/fakeglx.c b/src/mesa/drivers/x11/fakeglx.c index 3b004a3ee2..34e0b8bc8d 100644 --- a/src/mesa/drivers/x11/fakeglx.c +++ b/src/mesa/drivers/x11/fakeglx.c @@ -2218,7 +2218,7 @@ Fake_glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap, if (!dpy || !config || !pixmap) return 0; - for (attr = attribList; *attr; attr++) { + for (attr = attribList; attr && *attr; attr++) { switch (*attr) { case GLX_TEXTURE_FORMAT_EXT: attr++; diff --git a/src/mesa/main/compiler.h b/src/mesa/main/compiler.h index 93103fe878..e79bbc2ac5 100644 --- a/src/mesa/main/compiler.h +++ b/src/mesa/main/compiler.h @@ -468,9 +468,9 @@ do { \ #endif - +#ifndef Elements #define Elements(x) (sizeof(x)/sizeof(*(x))) - +#endif diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 7a9c69ac90..415e339cb8 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -1260,6 +1260,24 @@ initialize_framebuffer_size(GLcontext *ctx, GLframebuffer *fb) /** + * Check if the viewport/scissor size has not yet been initialized. + * Initialize the size if the given width and height are non-zero. + */ +void +_mesa_check_init_viewport(GLcontext *ctx, GLuint width, GLuint height) +{ + if (!ctx->ViewportInitialized && width > 0 && height > 0) { + /* Note: set flag here, before calling _mesa_set_viewport(), to prevent + * potential infinite recursion. + */ + ctx->ViewportInitialized = GL_TRUE; + _mesa_set_viewport(ctx, 0, 0, width, height); + _mesa_set_scissor(ctx, 0, 0, width, height); + } +} + + +/** * Bind the given context to the given drawBuffer and readBuffer and * make it the current context for the calling thread. * We'll render into the drawBuffer and read pixels from the @@ -1376,25 +1394,24 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer, ASSERT(drawBuffer->Height > 0); #endif - if (newCtx->FirstTimeCurrent) { - /* set initial viewport and scissor size now */ - _mesa_set_viewport(newCtx, 0, 0, - drawBuffer->Width, drawBuffer->Height); - _mesa_set_scissor(newCtx, 0, 0, - drawBuffer->Width, drawBuffer->Height ); - check_context_limits(newCtx); + if (drawBuffer) { + _mesa_check_init_viewport(newCtx, + drawBuffer->Width, drawBuffer->Height); } } - /* We can use this to help debug user's problems. Tell them to set - * the MESA_INFO env variable before running their app. Then the - * first time each context is made current we'll print some useful - * information. - */ if (newCtx->FirstTimeCurrent) { + check_context_limits(newCtx); + + /* We can use this to help debug user's problems. Tell them to set + * the MESA_INFO env variable before running their app. Then the + * first time each context is made current we'll print some useful + * information. + */ if (_mesa_getenv("MESA_INFO")) { _mesa_print_info(); } + newCtx->FirstTimeCurrent = GL_FALSE; } } diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h index 6b3e1b2b97..0531ae8ee8 100644 --- a/src/mesa/main/context.h +++ b/src/mesa/main/context.h @@ -130,6 +130,9 @@ extern void _mesa_copy_context(const GLcontext *src, GLcontext *dst, GLuint mask); +extern void +_mesa_check_init_viewport(GLcontext *ctx, GLuint width, GLuint height); + extern GLboolean _mesa_make_current( GLcontext *ctx, GLframebuffer *drawBuffer, GLframebuffer *readBuffer ); diff --git a/src/mesa/main/enums.c b/src/mesa/main/enums.c index 11f9a82e7c..7c62328fa9 100644 --- a/src/mesa/main/enums.c +++ b/src/mesa/main/enums.c @@ -958,8 +958,8 @@ LONGSTRING static const char enum_string_table[] = "GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV\0" "GL_MAX_VARYING_FLOATS\0" "GL_MAX_VARYING_FLOATS_ARB\0" - "GL_MAX_VERTEX_ATTRIBS\0" - "GL_MAX_VERTEX_ATTRIBS_ARB\0" + "GL_MAX_VERTEX_GENERIC_ATTRIBS\0" + "GL_MAX_VERTEX_GENERIC_ATTRIBS_ARB\0" "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS\0" "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB\0" "GL_MAX_VERTEX_UNIFORM_COMPONENTS\0" diff --git a/src/mesa/main/macros.h b/src/mesa/main/macros.h index 59def651a3..4ca7957ffa 100644 --- a/src/mesa/main/macros.h +++ b/src/mesa/main/macros.h @@ -83,28 +83,28 @@ extern GLfloat _mesa_ubyte_to_float_color_tab[256]; /** Convert GLuint in [0,4294967295] to GLfloat in [0.0,1.0] */ -#define UINT_TO_FLOAT(U) ((GLfloat) (U) * (1.0F / 4294967295.0F)) +#define UINT_TO_FLOAT(U) ((GLfloat) (U) * (1.0F / 4294967295.0)) /** Convert GLfloat in [0.0,1.0] to GLuint in [0,4294967295] */ -#define FLOAT_TO_UINT(X) ((GLuint) ((X) * 4294967295.0F)) +#define FLOAT_TO_UINT(X) ((GLuint) ((X) * 4294967295.0)) /** Convert GLint in [-2147483648,2147483647] to GLfloat in [-1.0,1.0] */ -#define INT_TO_FLOAT(I) ((2.0F * (I) + 1.0F) * (1.0F/4294967294.0F)) +#define INT_TO_FLOAT(I) ((2.0F * (I) + 1.0F) * (1.0F/4294967294.0)) /** Convert GLfloat in [-1.0,1.0] to GLint in [-2147483648,2147483647] */ /* causes overflow: -#define FLOAT_TO_INT(X) ( (((GLint) (4294967294.0F * (X))) - 1) / 2 ) +#define FLOAT_TO_INT(X) ( (((GLint) (4294967294.0 * (X))) - 1) / 2 ) */ /* a close approximation: */ -#define FLOAT_TO_INT(X) ( (GLint) (2147483647.0F * (X)) ) +#define FLOAT_TO_INT(X) ( (GLint) (2147483647.0 * (X)) ) /** Convert GLint in [-2147483648,2147483647] to GLfloat in [-1.0,1.0], texture/fb data */ -#define INT_TO_FLOAT_TEX(I) ((I) == -2147483648 ? -1.0F : (I) * (1.0F/2147483647.0F)) +#define INT_TO_FLOAT_TEX(I) ((I) == -2147483648 ? -1.0F : (I) * (1.0F/2147483647.0)) /** Convert GLfloat in [-1.0,1.0] to GLint in [-2147483648,2147483647], texture/fb data */ -#define FLOAT_TO_INT_TEX(X) ( (GLint) (2147483647.0F * (X)) ) +#define FLOAT_TO_INT_TEX(X) ( (GLint) (2147483647.0 * (X)) ) #define BYTE_TO_UBYTE(b) ((GLubyte) ((b) < 0 ? 0 : (GLubyte) (b))) diff --git a/src/mesa/main/mipmap.c b/src/mesa/main/mipmap.c index 872982fa43..3dca09d9f2 100644 --- a/src/mesa/main/mipmap.c +++ b/src/mesa/main/mipmap.c @@ -1601,9 +1601,6 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target, return; } - if (dstImage->ImageOffsets) - _mesa_free(dstImage->ImageOffsets); - /* Free old image data */ if (dstImage->Data) ctx->Driver.FreeTexImageData(ctx, dstImage); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 135eedbcab..e52278a7b2 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2053,6 +2053,7 @@ struct gl_shader_state struct gl_shader_program *CurrentProgram; /**< The user-bound program */ /** Driver-selectable options: */ GLboolean EmitHighLevelInstructions; /**< IF/ELSE/ENDIF vs. BRA, etc. */ + GLboolean EmitContReturn; /**< Emit CONT/RET opcodes? */ GLboolean EmitCondCodes; /**< Use condition codes? */ GLboolean EmitComments; /**< Annotated instructions */ void *MemPool; @@ -2981,6 +2982,8 @@ struct __GLcontextRec GLenum RenderMode; /**< either GL_RENDER, GL_SELECT, GL_FEEDBACK */ GLbitfield NewState; /**< bitwise-or of _NEW_* flags */ + GLboolean ViewportInitialized; /**< has viewport size been initialized? */ + GLbitfield varying_vp_inputs; /**< mask of VERT_BIT_* flags */ /** \name Derived state */ diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index 76b46d700b..6e21066537 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -1250,6 +1250,8 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target, * We allocate the array for 1D/2D textures too in order to avoid special- * case code in the texstore routines. */ + if (img->ImageOffsets) + _mesa_free(img->ImageOffsets); img->ImageOffsets = (GLuint *) _mesa_malloc(depth * sizeof(GLuint)); for (i = 0; i < depth; i++) { img->ImageOffsets[i] = i * width * height; diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index a8390d3094..648fbc186b 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -402,6 +402,7 @@ _mesa_init_shader_state(GLcontext * ctx) * are generated by the GLSL compiler. */ ctx->Shader.EmitHighLevelInstructions = GL_TRUE; + ctx->Shader.EmitContReturn = GL_TRUE; ctx->Shader.EmitCondCodes = GL_FALSE; ctx->Shader.EmitComments = GL_FALSE; ctx->Shader.Flags = get_shader_flags(); diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 6d693c9027..24e9952386 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -75,6 +75,11 @@ const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256; static slang_ir_node * _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper); +static void +slang_substitute(slang_assemble_ctx *A, slang_operation *oper, + GLuint substCount, slang_variable **substOld, + slang_operation **substNew, GLboolean isLHS); + /** * Retrieves type information about an operation. @@ -326,6 +331,17 @@ sampler_to_texture_index(const slang_type_specifier_type type) } +/** helper to build a SLANG_OPER_IDENTIFIER node */ +static void +slang_operation_identifier(slang_operation *oper, + slang_assemble_ctx *A, + const char *name) +{ + oper->type = SLANG_OPER_IDENTIFIER; + oper->a_id = slang_atom_pool_atom(A->atoms, name); +} + + #define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W) /** @@ -429,6 +445,56 @@ _slang_output_index(const char *name, GLenum target) } +/** + * Called when we begin code/IR generation for a new while/do/for loop. + */ +static void +push_loop(slang_assemble_ctx *A, slang_operation *loopOper, slang_ir_node *loopIR) +{ + A->LoopOperStack[A->LoopDepth] = loopOper; + A->LoopIRStack[A->LoopDepth] = loopIR; + A->LoopDepth++; +} + + +/** + * Called when we end code/IR generation for a new while/do/for loop. + */ +static void +pop_loop(slang_assemble_ctx *A) +{ + assert(A->LoopDepth > 0); + A->LoopDepth--; +} + + +/** + * Return pointer to slang_operation for the loop we're currently inside, + * or NULL if not in a loop. + */ +static const slang_operation * +current_loop_oper(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopOperStack[A->LoopDepth - 1]; + else + return NULL; +} + + +/** + * Return pointer to slang_ir_node for the loop we're currently inside, + * or NULL if not in a loop. + */ +static slang_ir_node * +current_loop_ir(const slang_assemble_ctx *A) +{ + if (A->LoopDepth > 0) + return A->LoopIRStack[A->LoopDepth - 1]; + else + return NULL; +} + /**********************************************************************/ @@ -636,7 +702,7 @@ new_break(slang_ir_node *loopNode) assert(loopNode); assert(loopNode->Opcode == IR_LOOP); if (n) { - /* insert this node at head of linked list */ + /* insert this node at head of linked list of cont/break instructions */ n->List = loopNode->List; loopNode->List = n; } @@ -648,14 +714,15 @@ new_break(slang_ir_node *loopNode) * Make new IR_BREAK_IF_TRUE. */ static slang_ir_node * -new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond) +new_break_if_true(slang_assemble_ctx *A, slang_ir_node *cond) { + slang_ir_node *loopNode = current_loop_ir(A); slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); n = new_node1(IR_BREAK_IF_TRUE, cond); if (n) { - /* insert this node at head of linked list */ + /* insert this node at head of linked list of cont/break instructions */ n->List = loopNode->List; loopNode->List = n; } @@ -667,14 +734,16 @@ new_break_if_true(slang_ir_node *loopNode, slang_ir_node *cond) * Make new IR_CONT_IF_TRUE node. */ static slang_ir_node * -new_cont_if_true(slang_ir_node *loopNode, slang_ir_node *cond) +new_cont_if_true(slang_assemble_ctx *A, slang_ir_node *cond) { + slang_ir_node *loopNode = current_loop_ir(A); slang_ir_node *n; assert(loopNode); assert(loopNode->Opcode == IR_LOOP); n = new_node1(IR_CONT_IF_TRUE, cond); if (n) { - /* insert this node at head of linked list */ + n->Parent = loopNode; /* pointer to containing loop */ + /* insert this node at head of linked list of cont/break instructions */ n->List = loopNode->List; loopNode->List = n; } @@ -749,6 +818,7 @@ _slang_is_noop(const slang_operation *oper) /** * Recursively search tree for a node of the given type. */ +#if 0 static slang_operation * _slang_find_node_type(slang_operation *oper, slang_operation_type type) { @@ -762,13 +832,14 @@ _slang_find_node_type(slang_operation *oper, slang_operation_type type) } return NULL; } +#endif /** * Count the number of operations of the given time rooted at 'oper'. */ static GLuint -_slang_count_node_type(slang_operation *oper, slang_operation_type type) +_slang_count_node_type(const slang_operation *oper, slang_operation_type type) { GLuint i, count = 0; if (oper->type == type) { @@ -822,6 +893,37 @@ _slang_is_tail_return(const slang_operation *oper) } +/** + * Generate a variable declaration opeartion. + * I.e.: generate AST code for "bool flag = false;" + */ +static void +slang_generate_declaration(slang_assemble_ctx *A, + slang_variable_scope *scope, + slang_operation *decl, + slang_type_specifier_type type, + const char *name, + GLint initValue) +{ + slang_variable *var; + + assert(type == SLANG_SPEC_BOOL || + type == SLANG_SPEC_INT); + + decl->type = SLANG_OPER_VARIABLE_DECL; + + var = slang_variable_scope_grow(scope); + + slang_fully_specified_type_construct(&var->type); + + var->type.specifier.type = type; + var->a_name = slang_atom_pool_atom(A->atoms, name); + decl->a_id = var->a_name; + var->initializer = slang_operation_new(1); + slang_operation_literal_bool(var->initializer, initValue); +} + + static void slang_resolve_variable(slang_operation *oper) { @@ -832,6 +934,159 @@ slang_resolve_variable(slang_operation *oper) /** + * Rewrite AST code for "return expression;". + * + * We return values from functions by assinging the returned value to + * the hidden __retVal variable which is an extra 'out' parameter we add + * to the function signature. + * This code basically converts "return expr;" into "__retVal = expr; return;" + * + * \return the new AST code. + */ +static slang_operation * +gen_return_with_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *blockOper, *assignOper; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "illegal return expression"); + return NULL; + } + + blockOper = slang_operation_new(1); + blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + blockOper->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(blockOper, 2); + + if (A->UseReturnFlag) { + /* Emit: + * { + * if (__notRetFlag) + * __retVal = expr; + * __notRetFlag = 0; + * } + */ + { + slang_operation *ifOper = slang_oper_child(blockOper, 0); + ifOper->type = SLANG_OPER_IF; + slang_operation_add_children(ifOper, 3); + { + slang_operation *cond = slang_oper_child(ifOper, 0); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *elseOper = slang_oper_child(ifOper, 2); + elseOper->type = SLANG_OPER_VOID; + } + assignOper = slang_oper_child(ifOper, 1); + } + { + slang_operation *setOper = slang_oper_child(blockOper, 1); + setOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(setOper, 2); + { + slang_operation *lhs = slang_oper_child(setOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(setOper, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * { + * __retVal = expr; + * return_inlined; + * } + */ + assignOper = slang_oper_child(blockOper, 0); + { + slang_operation *returnOper = slang_oper_child(blockOper, 1); + returnOper->type = SLANG_OPER_RETURN_INLINED; + assert(returnOper->num_children == 0); + } + } + + /* __retVal = expression; */ + assignOper->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assignOper, 2); + { + slang_operation *lhs = slang_oper_child(assignOper, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__retVal"); + } + { + slang_operation *rhs = slang_oper_child(assignOper, 1); + slang_operation_copy(rhs, &oper->children[0]); + } + + ///blockOper->locals->outer_scope = oper->locals->outer_scope; + + /*slang_print_tree(blockOper, 0);*/ + + return blockOper; +} + + +/** + * Rewrite AST code for "return;" (no expression). + */ +static slang_operation * +gen_return_without_expression(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *newRet; + + assert(oper->type == SLANG_OPER_RETURN); + + if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { + slang_info_log_error(A->log, "return statement requires an expression"); + return NULL; + } + + if (A->UseReturnFlag) { + /* Emit: + * __notRetFlag = 0; + */ + { + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(newRet, 2); + { + slang_operation *lhs = slang_oper_child(newRet, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + } + { + slang_operation *rhs = slang_oper_child(newRet, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + } + else { + /* Emit: + * return_inlined; + */ + newRet = slang_operation_new(1); + newRet->locals->outer_scope = oper->locals->outer_scope; + newRet->type = SLANG_OPER_RETURN_INLINED; + } + + /*slang_print_tree(newRet, 0);*/ + + return newRet; +} + + + + +/** * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions. */ static void @@ -866,7 +1121,8 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, GLuint i; v = _slang_variable_locate(oper->locals, id, GL_TRUE); if (!v) { - _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); + if (_mesa_strcmp((char *) oper->a_id, "__notRetFlag")) + _mesa_problem(NULL, "var %s not found!\n", (char *) oper->a_id); return; } @@ -896,62 +1152,24 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper, break; case SLANG_OPER_RETURN: - /* do return replacement here too */ - assert(oper->num_children == 0 || oper->num_children == 1); - if (oper->num_children == 1 && !_slang_is_noop(&oper->children[0])) { - /* replace: - * return expr; - * with: - * __retVal = expr; - * return; - * then do substitutions on the assignment. - */ - slang_operation *blockOper, *assignOper, *returnOper; + { + slang_operation *newReturn; + /* generate new 'return' code' */ + if (slang_oper_child(oper, 0)->type == SLANG_OPER_VOID) + newReturn = gen_return_without_expression(A, oper); + else + newReturn = gen_return_with_expression(A, oper); - /* check if function actually has a return type */ - assert(A->CurFunction); - if (A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "illegal return expression"); + if (!newReturn) return; - } - - blockOper = slang_operation_new(1); - blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; - blockOper->num_children = 2; - blockOper->locals->outer_scope = oper->locals->outer_scope; - blockOper->children = slang_operation_new(2); - assignOper = blockOper->children + 0; - returnOper = blockOper->children + 1; - - assignOper->type = SLANG_OPER_ASSIGN; - assignOper->num_children = 2; - assignOper->locals->outer_scope = blockOper->locals; - assignOper->children = slang_operation_new(2); - assignOper->children[0].type = SLANG_OPER_IDENTIFIER; - assignOper->children[0].a_id = slang_atom_pool_atom(A->atoms, "__retVal"); - assignOper->children[0].locals->outer_scope = assignOper->locals; - - slang_operation_copy(&assignOper->children[1], - &oper->children[0]); - - returnOper->type = SLANG_OPER_RETURN; /* return w/ no value */ - assert(returnOper->num_children == 0); - /* do substitutions on the "__retVal = expr" sub-tree */ - slang_substitute(A, assignOper, + /* do substitutions on the new 'return' code */ + slang_substitute(A, newReturn, substCount, substOld, substNew, GL_FALSE); - /* install new code */ - slang_operation_copy(oper, blockOper); - slang_operation_destruct(blockOper); - } - else { - /* check if return value was expected */ - assert(A->CurFunction); - if (A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "return statement requires an expression"); - return; - } + /* install new 'return' code */ + slang_operation_copy(oper, newReturn); + slang_operation_destruct(newReturn); } break; @@ -1346,12 +1564,74 @@ slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun, } +/** + * Insert declaration for "bool __notRetFlag" in given block operation. + * This is used when we can't emit "early" return statements in subroutines. + */ +static void +declare_return_flag(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *decl; + + assert(oper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + oper->type == SLANG_OPER_SEQUENCE); + + decl = slang_operation_insert_child(oper, 1); + + slang_generate_declaration(A, oper->locals, decl, + SLANG_SPEC_BOOL, "__notRetFlag", GL_TRUE); + + /*slang_print_tree(oper, 0);*/ +} + + +/** + * Recursively replace instances of the old node type with the new type. + */ +static void +replace_node_type(slang_operation *oper, slang_operation_type oldType, + slang_operation_type newType) +{ + GLuint i; + + if (oper->type == oldType) + oper->type = newType; + + for (i = 0; i < slang_oper_num_children(oper); i++) { + replace_node_type(slang_oper_child(oper, i), oldType, newType); + } +} + + + +/** + * Test if the given function body has an "early return". That is, there's + * a 'return' statement that's not the very last instruction in the body. + */ +static GLboolean +has_early_return(const slang_operation *funcBody) +{ + GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN); + if (retCount == 0) + return GL_FALSE; + else if (retCount == 1 && _slang_is_tail_return(funcBody)) + return GL_FALSE; + else + return GL_TRUE; +} + + +/** + * Emit IR code for a function call. This does one of two things: + * 1. Inline the function's code + * 2. Create an IR for the function's body and create a real call to it. + */ static slang_ir_node * _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, slang_operation *oper, slang_operation *dest) { slang_ir_node *n; - slang_operation *inlined; + slang_operation *instance; slang_label *prevFuncEndLabel; char name[200]; @@ -1360,9 +1640,14 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, A->curFuncEndLabel = _slang_label_new(name); assert(A->curFuncEndLabel); + /* + * 'instance' is basically a copy of the function's body with various + * transformations. + */ + if (slang_is_asm_function(fun) && !dest) { /* assemble assembly function - tree style */ - inlined = slang_inline_asm_function(A, fun, oper); + instance = slang_inline_asm_function(A, fun, oper); } else { /* non-assembly function */ @@ -1371,65 +1656,82 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, * 1. insert the inline code * 2. Generate a call to the "inline" code as a subroutine */ + const GLboolean earlyReturn = has_early_return(fun->body); + if (earlyReturn && !A->EmitContReturn) { + A->UseReturnFlag = GL_TRUE; + } - slang_operation *ret = NULL; - - inlined = slang_inline_function_call(A, fun, oper, dest); - if (!inlined) + instance = slang_inline_function_call(A, fun, oper, dest); + if (!instance) return NULL; - ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN); - if (ret) { - /* check if this is a "tail" return */ - if (_slang_count_node_type(inlined, SLANG_OPER_RETURN) == 1 && - _slang_is_tail_return(inlined)) { - /* The only RETURN is the last stmt in the function, no-op it - * and inline the function body. + if (earlyReturn) { + /* The function we're calling has one or more 'return' statements + * that prevent us from inlining the function's code. + * + * In this case, change the function's body type from + * SLANG_OPER_BLOCK_NEW_SCOPE to SLANG_OPER_NON_INLINED_CALL. + * During code emit this will result in a true subroutine call. + * + * Also, convert SLANG_OPER_RETURN_INLINED nodes to SLANG_OPER_RETURN. + */ + slang_operation *callOper; + + assert(instance->type == SLANG_OPER_BLOCK_NEW_SCOPE || + instance->type == SLANG_OPER_SEQUENCE); + + if (_slang_function_has_return_value(fun) && !dest) { + assert(instance->children[0].type == SLANG_OPER_VARIABLE_DECL); + assert(instance->children[2].type == SLANG_OPER_IDENTIFIER); + callOper = &instance->children[1]; + } + else { + callOper = instance; + } + + if (A->UseReturnFlag) { + /* Early returns not supported. Create a _returnFlag variable + * that's set upon 'return' and tested elsewhere to no-op any + * remaining instructions in the subroutine. */ - ret->type = SLANG_OPER_NONE; + assert(callOper->type == SLANG_OPER_BLOCK_NEW_SCOPE || + callOper->type == SLANG_OPER_SEQUENCE); + declare_return_flag(A, callOper); } else { - slang_operation *callOper; - /* The function we're calling has one or more 'return' statements. - * So, we can't truly inline this function because we need to - * implement 'return' with RET (and CAL). - * Nevertheless, we performed "inlining" to make a new instance - * of the function body to deal with static register allocation. - * - * XXX check if there's one 'return' and if it's the very last - * statement in the function - we can optimize that case. + /* We can emit real 'return' statements. If we generated any + * 'inline return' statements during function instantiation, + * change them back to regular 'return' statements. */ - assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE || - inlined->type == SLANG_OPER_SEQUENCE); - - if (_slang_function_has_return_value(fun) && !dest) { - assert(inlined->children[0].type == SLANG_OPER_VARIABLE_DECL); - assert(inlined->children[2].type == SLANG_OPER_IDENTIFIER); - callOper = &inlined->children[1]; - } - else { - callOper = inlined; - } - callOper->type = SLANG_OPER_NON_INLINED_CALL; - callOper->fun = fun; - callOper->label = _slang_label_new_unique((char*) fun->header.a_name); + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_RETURN); } + + callOper->type = SLANG_OPER_NON_INLINED_CALL; + callOper->fun = fun; + callOper->label = _slang_label_new_unique((char*) fun->header.a_name); + } + else { + /* If there are any 'return' statements remaining, they're at the + * very end of the function and can effectively become no-ops. + */ + replace_node_type(instance, SLANG_OPER_RETURN_INLINED, + SLANG_OPER_VOID); } } - if (!inlined) + if (!instance) return NULL; - /* Replace the function call with the inlined block (or new CALL stmt) */ + /* Replace the function call with the instance block (or new CALL stmt) */ slang_operation_destruct(oper); - *oper = *inlined; - _slang_free(inlined); + *oper = *instance; + _slang_free(instance); #if 0 - assert(inlined->locals); - printf("*** Inlined code for call to %s:\n", - (char*) fun->header.a_name); + assert(instance->locals); + printf("*** Inlined code for call to %s:\n", (char*) fun->header.a_name); slang_print_tree(oper, 10); printf("\n"); #endif @@ -1445,6 +1747,8 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun, n->Comment = _slang_strdup(s); } + A->UseReturnFlag = GL_FALSE; + return n; } @@ -2337,19 +2641,252 @@ _slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper) /** + * Check if a loop contains a 'continue' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + const slang_operation *child = slang_oper_child_const(oper, i); + if (_slang_loop_contains_continue(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Check if a loop contains a 'continue' or 'break' statement. + * Stop looking if we find a nested loop. + */ +static GLboolean +_slang_loop_contains_continue_or_break(const slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + case SLANG_OPER_BREAK: + return GL_TRUE; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + return GL_FALSE; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + const slang_operation *child = slang_oper_child_const(oper, i); + if (_slang_loop_contains_continue_or_break(child)) + return GL_TRUE; + } + } + return GL_FALSE; + } +} + + +/** + * Replace 'break' and 'continue' statements inside a do and while loops. + * This is a recursive helper function used by + * _slang_gen_do/while_without_continue(). + */ +static void +replace_break_and_cont(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_BREAK: + /* replace 'break' with "_notBreakFlag = false; break" */ + { + slang_operation *block = oper; + block->type = SLANG_OPER_BLOCK_NEW_SCOPE; + slang_operation_add_children(block, 2); + { + slang_operation *assign = slang_oper_child(block, 0); + assign->type = SLANG_OPER_ASSIGN; + slang_operation_add_children(assign, 2); + { + slang_operation *lhs = slang_oper_child(assign, 0); + slang_operation_identifier(lhs, A, "_notBreakFlag"); + } + { + slang_operation *rhs = slang_oper_child(assign, 1); + slang_operation_literal_bool(rhs, GL_FALSE); + } + } + { + slang_operation *brk = slang_oper_child(block, 1); + brk->type = SLANG_OPER_BREAK; + assert(!brk->children); + } + } + break; + case SLANG_OPER_CONTINUE: + /* convert continue into a break */ + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_break_and_cont(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * while (LOOPCOND) { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } + * + * After: + * + * { + * bool _notBreakFlag = 1; + * while (_notBreakFlag && LOOPCOND) { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } + * } + */ +static slang_ir_node * +_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_WHILE); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); + } + + /* build outer while-loop: while (_notBreakFlag && LOOPCOND) { ... } */ + { + slang_operation *outerWhile = slang_oper_child(top, 1); + outerWhile->type = SLANG_OPER_WHILE; + slang_operation_add_children(outerWhile, 2); + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerWhile, 0); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 0)); + } + } + + /* inner loop */ + { + slang_operation *innerDo = slang_oper_child(outerWhile, 1); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 1)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + /*slang_print_tree(top, 0);*/ + + return _slang_gen_operation(A, top); + + return NULL; +} + + +/** * Generate loop code using high-level IR_LOOP instruction */ static slang_ir_node * -_slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_while(slang_assemble_ctx * A, slang_operation *oper) { /* * LOOP: * BREAK if !expr (child[0]) * body code (child[1]) */ - slang_ir_node *prevLoop, *loop, *breakIf, *body; + slang_ir_node *loop, *breakIf, *body; GLboolean isConst, constTrue; + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this while-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) { + return _slang_gen_while_without_continue(A, oper); + } + } + /* type-check expression */ if (!_slang_is_boolean(A, &oper->children[0])) { slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'"); @@ -2364,11 +2901,11 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) return new_node0(IR_NOP); } + /* Begin new loop */ loop = new_loop(NULL); - /* save old, push new loop */ - prevLoop = A->CurLoop; - A->CurLoop = loop; + /* save loop state */ + push_loop(A, oper, loop); if (isConst && constTrue) { /* while(nonzero constant), no conditional break */ @@ -2377,7 +2914,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) else { slang_ir_node *cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[0]))); - breakIf = new_break_if_true(A->CurLoop, cond); + breakIf = new_break_if_true(A, cond); } body = _slang_gen_operation(A, &oper->children[1]); loop->Children[0] = new_seq(breakIf, body); @@ -2386,23 +2923,128 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper) /* loop->List is head of linked list of break/continue nodes */ if (!loop->List && isConst && constTrue) { /* infinite loop detected */ - A->CurLoop = prevLoop; /* clean-up */ + pop_loop(A); slang_info_log_error(A->log, "Infinite loop detected!"); return NULL; } - /* pop loop, restore prev */ - A->CurLoop = prevLoop; + /* restore loop state */ + pop_loop(A); return loop; } /** + * Transform a do-while-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * do { + * A; + * if (IFCOND) + * continue; + * B; + * break; + * C; + * } while (LOOPCOND); + * + * After: + * + * { + * bool _notBreakFlag = 1; + * do { + * do { + * A; + * if (IFCOND) { + * break; // was continue + * } + * B; + * _notBreakFlag = 0; // was + * break; // break + * C; + * } while (0) + * } while (_notBreakFlag && LOOPCOND); + * } + */ +static slang_ir_node * +_slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *innerBody; + + assert(oper->type == SLANG_OPER_DO); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _notBreakFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_notBreakFlag", GL_TRUE); + } + + /* build outer do-loop: do { ... } while (_notBreakFlag && LOOPCOND) */ + { + slang_operation *outerDo = slang_oper_child(top, 1); + outerDo->type = SLANG_OPER_DO; + slang_operation_add_children(outerDo, 2); + + /* inner do-loop */ + { + slang_operation *innerDo = slang_oper_child(outerDo, 0); + innerDo->type = SLANG_OPER_DO; + slang_operation_add_children(innerDo, 2); + + /* copy original do-loop body into inner do-loop's body */ + innerBody = slang_oper_child(innerDo, 0); + slang_operation_copy(innerBody, slang_oper_child(oper, 0)); + innerBody->locals->outer_scope = innerDo->locals; + + /* inner do-loop's condition is constant/false */ + { + slang_operation *constFalse = slang_oper_child(innerDo, 1); + slang_operation_literal_bool(constFalse, GL_FALSE); + } + } + + /* _notBreakFlag && LOOPCOND */ + { + slang_operation *cond = slang_oper_child(outerDo, 1); + cond->type = SLANG_OPER_LOGICALAND; + slang_operation_add_children(cond, 2); + { + slang_operation *notBreak = slang_oper_child(cond, 0); + slang_operation_identifier(notBreak, A, "_notBreakFlag"); + } + { + slang_operation *origCond = slang_oper_child(cond, 1); + slang_operation_copy(origCond, slang_oper_child(oper, 1)); + } + } + } + + /* Finally, in innerBody, + * replace "break" with "_notBreakFlag = 0; break" + * replace "continue" with "break" + */ + replace_break_and_cont(A, innerBody); + + /*slang_print_tree(top, 0);*/ + + return _slang_gen_operation(A, top); +} + + +/** * Generate IR tree for a do-while loop using high-level LOOP, IF instructions. */ static slang_ir_node * -_slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper) { /* * LOOP: @@ -2410,9 +3052,18 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) * tail code: * BREAK if !expr (child[1]) */ - slang_ir_node *prevLoop, *loop; + slang_ir_node *loop; GLboolean isConst, constTrue; + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this do-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) { + return _slang_gen_do_without_continue(A, oper); + } + } + /* type-check expression */ if (!_slang_is_boolean(A, &oper->children[1])) { slang_info_log_error(A->log, "scalar/boolean expression expected for 'do/while'"); @@ -2421,9 +3072,8 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) loop = new_loop(NULL); - /* save old, push new loop */ - prevLoop = A->CurLoop; - A->CurLoop = loop; + /* save loop state */ + push_loop(A, oper, loop); /* loop body: */ loop->Children[0] = _slang_gen_operation(A, &oper->children[0]); @@ -2437,13 +3087,13 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper) else { slang_ir_node *cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); - loop->Children[1] = new_break_if_true(A->CurLoop, cond); + loop->Children[1] = new_break_if_true(A, cond); } /* XXX we should do infinite loop detection, as above */ - /* pop loop, restore prev */ - A->CurLoop = prevLoop; + /* restore loop state */ + pop_loop(A); return loop; } @@ -2485,9 +3135,14 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) const char *varName; slang_atom varId; - assert(oper->type == SLANG_OPER_FOR); + if (oper->type != SLANG_OPER_FOR) + return GL_FALSE; + assert(oper->num_children == 4); + if (_slang_loop_contains_continue_or_break(slang_oper_child_const(oper, 3))) + return GL_FALSE; + /* children[0] must be either "int i=constant" or "i=constant" */ if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { slang_variable *var; @@ -2582,20 +3237,6 @@ _slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) } -static void -_unroll_loop_inc(slang_assemble_ctx * A) -{ - A->UnrollLoop++; -} - - -static void -_unroll_loop_dec(slang_assemble_ctx * A) -{ - A->UnrollLoop--; -} - - /** * Unroll a for-loop. * First we determine the number of iterations to unroll. @@ -2612,9 +3253,6 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) slang_ir_node *n, *root = NULL; slang_atom varId; - /* Set flag so code generator knows we're unrolling loops */ - _unroll_loop_inc( A ); - if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) { /* for (int i=0; ... */ slang_variable *var; @@ -2637,15 +3275,11 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) /* make a copy of the loop body */ body = slang_operation_new(1); - if (!body) { - _unroll_loop_dec( A ); + if (!body) return NULL; - } - if (!slang_operation_copy(body, &oper->children[3])) { - _unroll_loop_dec( A ); + if (!slang_operation_copy(body, &oper->children[3])) return NULL; - } /* in body, replace instances of 'varId' with literal 'iter' */ { @@ -2656,7 +3290,6 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) if (!oldVar) { /* undeclared loop variable */ slang_operation_delete(body); - _unroll_loop_dec( A ); return NULL; } @@ -2671,36 +3304,195 @@ _slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper) /* do IR codegen for body */ n = _slang_gen_operation(A, body); - if (!n) { - _unroll_loop_dec( A ); + if (!n) return NULL; - } root = new_seq(root, n); slang_operation_delete(body); } - _unroll_loop_dec( A ); - return root; } /** + * Replace 'continue' statement with 'break' inside a for-loop. + * This is a recursive helper function used by _slang_gen_for_without_continue(). + */ +static void +replace_continue_with_break(slang_assemble_ctx *A, slang_operation *oper) +{ + switch (oper->type) { + case SLANG_OPER_CONTINUE: + oper->type = SLANG_OPER_BREAK; + break; + case SLANG_OPER_FOR: + case SLANG_OPER_DO: + case SLANG_OPER_WHILE: + /* stop upon finding a nested loop */ + break; + default: + /* recurse */ + { + GLuint i; + for (i = 0; i < oper->num_children; i++) { + replace_continue_with_break(A, slang_oper_child(oper, i)); + } + } + } +} + + +/** + * Transform a for-loop so that continue statements are converted to breaks. + * Then do normal IR code generation. + * + * Before: + * + * for (INIT; LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * continue; + * } + * B; + * } + * + * After: + * + * { + * bool _condFlag = 1; + * for (INIT; _condFlag; ) { + * for ( ; _condFlag = LOOPCOND; INCR) { + * A; + * if (IFCOND) { + * break; + * } + * B; + * } + * if (_condFlag) + * INCR; + * } + * } + */ +static slang_ir_node * +_slang_gen_for_without_continue(slang_assemble_ctx *A, slang_operation *oper) +{ + slang_operation *top; + slang_operation *outerFor, *innerFor, *init, *cond, *incr; + slang_operation *lhs, *rhs; + + assert(oper->type == SLANG_OPER_FOR); + + top = slang_operation_new(1); + top->type = SLANG_OPER_BLOCK_NEW_SCOPE; + top->locals->outer_scope = oper->locals->outer_scope; + slang_operation_add_children(top, 2); + + /* declare: bool _condFlag = true */ + { + slang_operation *condDecl = slang_oper_child(top, 0); + slang_generate_declaration(A, top->locals, condDecl, + SLANG_SPEC_BOOL, "_condFlag", GL_TRUE); + } + + /* build outer loop: for (INIT; _condFlag; ) { */ + outerFor = slang_oper_child(top, 1); + outerFor->type = SLANG_OPER_FOR; + slang_operation_add_children(outerFor, 4); + + init = slang_oper_child(outerFor, 0); + slang_operation_copy(init, slang_oper_child(oper, 0)); + + cond = slang_oper_child(outerFor, 1); + cond->type = SLANG_OPER_IDENTIFIER; + cond->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + incr = slang_oper_child(outerFor, 2); + incr->type = SLANG_OPER_VOID; + + /* body of the outer loop */ + { + slang_operation *block = slang_oper_child(outerFor, 3); + + slang_operation_add_children(block, 2); + block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + + /* build inner loop: for ( ; _condFlag = LOOPCOND; INCR) { */ + { + innerFor = slang_oper_child(block, 0); + + /* make copy of orig loop */ + slang_operation_copy(innerFor, oper); + assert(innerFor->type == SLANG_OPER_FOR); + innerFor->locals->outer_scope = block->locals; + + init = slang_oper_child(innerFor, 0); + init->type = SLANG_OPER_VOID; /* leak? */ + + cond = slang_oper_child(innerFor, 1); + slang_operation_destruct(cond); + cond->type = SLANG_OPER_ASSIGN; + cond->locals = _slang_variable_scope_new(innerFor->locals); + slang_operation_add_children(cond, 2); + + lhs = slang_oper_child(cond, 0); + lhs->type = SLANG_OPER_IDENTIFIER; + lhs->a_id = slang_atom_pool_atom(A->atoms, "_condFlag"); + + rhs = slang_oper_child(cond, 1); + slang_operation_copy(rhs, slang_oper_child(oper, 1)); + } + + /* if (_condFlag) INCR; */ + { + slang_operation *ifop = slang_oper_child(block, 1); + ifop->type = SLANG_OPER_IF; + slang_operation_add_children(ifop, 2); + + /* re-use cond node build above */ + slang_operation_copy(slang_oper_child(ifop, 0), cond); + + /* incr node from original for-loop operation */ + slang_operation_copy(slang_oper_child(ifop, 1), + slang_oper_child(oper, 2)); + } + + /* finally, replace "continue" with "break" in the inner for-loop */ + replace_continue_with_break(A, slang_oper_child(innerFor, 3)); + } + + return _slang_gen_operation(A, top); +} + + + +/** * Generate IR for a for-loop. Unrolling will be done when possible. */ static slang_ir_node * -_slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) +_slang_gen_for(slang_assemble_ctx * A, slang_operation *oper) { - GLboolean unroll = _slang_can_unroll_for_loop(A, oper); + GLboolean unroll; + + if (!A->EmitContReturn) { + /* We don't want to emit CONT instructions. If this for-loop has + * a continue, translate it away. + */ + if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) { + return _slang_gen_for_without_continue(A, oper); + } + } + unroll = _slang_can_unroll_for_loop(A, oper); if (unroll) { slang_ir_node *code = _slang_unroll_for_loop(A, oper); if (code) return code; } + assert(oper->type == SLANG_OPER_FOR); + /* conventional for-loop code generation */ { /* @@ -2711,24 +3503,23 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) * tail code: * incr code (child[2]) // XXX continue here */ - slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr; + slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr; init = _slang_gen_operation(A, &oper->children[0]); loop = new_loop(NULL); - /* save old, push new loop */ - prevLoop = A->CurLoop; - A->CurLoop = loop; + /* save loop state */ + push_loop(A, oper, loop); cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1]))); - breakIf = new_break_if_true(A->CurLoop, cond); + breakIf = new_break_if_true(A, cond); body = _slang_gen_operation(A, &oper->children[3]); incr = _slang_gen_operation(A, &oper->children[2]); loop->Children[0] = new_seq(breakIf, body); loop->Children[1] = incr; /* tail code */ - /* pop loop, restore prev */ - A->CurLoop = prevLoop; + /* restore loop state */ + pop_loop(A); return new_seq(init, loop); } @@ -2738,18 +3529,22 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper) static slang_ir_node * _slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper) { - slang_ir_node *n, *loopNode; + slang_ir_node *n, *cont, *incr = NULL, *loopNode; + assert(oper->type == SLANG_OPER_CONTINUE); - loopNode = A->CurLoop; + loopNode = current_loop_ir(A); assert(loopNode); assert(loopNode->Opcode == IR_LOOP); - n = new_node0(IR_CONT); - if (n) { - n->Parent = loopNode; - /* insert this node at head of linked list */ - n->List = loopNode->List; - loopNode->List = n; + + cont = new_node0(IR_CONT); + if (cont) { + cont->Parent = loopNode; + /* insert this node at head of linked list of cont/break instructions */ + cont->List = loopNode->List; + loopNode->List = cont; } + + n = new_seq(incr, cont); return n; } @@ -2819,24 +3614,20 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper) if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK) && !haveElseClause) { /* Special case: generate a conditional break */ - if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */ - return NULL; - ifBody = new_break_if_true(A->CurLoop, cond); + ifBody = new_break_if_true(A, cond); return ifBody; } else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE) - && !haveElseClause) { + && !haveElseClause + && current_loop_oper(A) + && current_loop_oper(A)->type != SLANG_OPER_FOR) { /* Special case: generate a conditional continue */ - if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */ - return NULL; - ifBody = new_cont_if_true(A->CurLoop, cond); + ifBody = new_cont_if_true(A, cond); return ifBody; } else { /* general case */ ifBody = _slang_gen_operation(A, &oper->children[1]); - if (!ifBody) - return NULL; if (haveElseClause) elseBody = _slang_gen_operation(A, &oper->children[2]); else @@ -3242,14 +4033,11 @@ _slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper) select = slang_operation_new(1); select->type = SLANG_OPER_SELECT; - select->num_children = 3; - select->children = slang_operation_new(3); + slang_operation_add_children(select, 3); - slang_operation_copy(&select->children[0], &oper->children[0]); - slang_operation_copy(&select->children[1], &oper->children[1]); - select->children[2].type = SLANG_OPER_LITERAL_BOOL; - ASSIGN_4V(select->children[2].literal, 0, 0, 0, 0); /* false */ - select->children[2].literal_size = 1; + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_copy(slang_oper_child(select, 1), &oper->children[1]); + slang_operation_literal_bool(slang_oper_child(select, 2), GL_FALSE); n = _slang_gen_select(A, select); return n; @@ -3268,14 +4056,11 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) select = slang_operation_new(1); select->type = SLANG_OPER_SELECT; - select->num_children = 3; - select->children = slang_operation_new(3); + slang_operation_add_children(select, 3); - slang_operation_copy(&select->children[0], &oper->children[0]); - select->children[1].type = SLANG_OPER_LITERAL_BOOL; - ASSIGN_4V(select->children[1].literal, 1, 1, 1, 1); /* true */ - select->children[1].literal_size = 1; - slang_operation_copy(&select->children[2], &oper->children[1]); + slang_operation_copy(slang_oper_child(select, 0), &oper->children[0]); + slang_operation_literal_bool(slang_oper_child(select, 1), GL_TRUE); + slang_operation_copy(slang_oper_child(select, 2), &oper->children[1]); n = _slang_gen_select(A, select); return n; @@ -3288,70 +4073,8 @@ _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper) static slang_ir_node * _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper) { - const GLboolean haveReturnValue - = (oper->num_children == 1 && oper->children[0].type != SLANG_OPER_VOID); - - /* error checking */ - assert(A->CurFunction); - if (haveReturnValue && - A->CurFunction->header.type.specifier.type == SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "illegal return expression"); - return NULL; - } - else if (!haveReturnValue && - A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) { - slang_info_log_error(A->log, "return statement requires an expression"); - return NULL; - } - - if (!haveReturnValue) { - return new_return(A->curFuncEndLabel); - } - else { - /* - * Convert from: - * return expr; - * To: - * __retVal = expr; - * return; // goto __endOfFunction - */ - slang_operation *assign; - slang_atom a_retVal; - slang_ir_node *n; - - a_retVal = slang_atom_pool_atom(A->atoms, "__retVal"); - assert(a_retVal); - -#if 1 /* DEBUG */ - { - slang_variable *v = - _slang_variable_locate(oper->locals, a_retVal, GL_TRUE); - if (!v) { - /* trying to return a value in a void-valued function */ - return NULL; - } - } -#endif - - assign = slang_operation_new(1); - assign->type = SLANG_OPER_ASSIGN; - assign->num_children = 2; - assign->children = slang_operation_new(2); - /* lhs (__retVal) */ - assign->children[0].type = SLANG_OPER_IDENTIFIER; - assign->children[0].a_id = a_retVal; - assign->children[0].locals->outer_scope = assign->locals; - /* rhs (expr) */ - /* XXX we might be able to avoid this copy someday */ - slang_operation_copy(&assign->children[1], &oper->children[0]); - - /* assemble the new code */ - n = new_seq(_slang_gen_operation(A, assign), - new_return(A->curFuncEndLabel)); - - slang_operation_delete(assign); - return n; - } + assert(oper->type == SLANG_OPER_RETURN); + return new_return(A->curFuncEndLabel); } @@ -3457,6 +4180,7 @@ _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper) assert(oper->type == SLANG_OPER_VARIABLE_DECL); assert(oper->num_children <= 1); + /* lookup the variable by name */ var = _slang_variable_locate(oper->locals, oper->a_id, GL_TRUE); if (!var) @@ -3612,6 +4336,9 @@ root_swizzle(const slang_ir_storage *st) static slang_ir_node * _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) { + slang_operation *pred = NULL; + slang_ir_node *n = NULL; + if (oper->children[0].type == SLANG_OPER_IDENTIFIER) { /* Check that var is writeable */ slang_variable *var @@ -3632,6 +4359,17 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) (char *) oper->children[0].a_id); return NULL; } + + /* check if we need to predicate this assignment based on __notRetFlag */ + if ((var->is_global || + var->type.qualifier == SLANG_QUAL_OUT || + var->type.qualifier == SLANG_QUAL_INOUT) && A->UseReturnFlag) { + /* create predicate, used below */ + pred = slang_operation_new(1); + pred->type = SLANG_OPER_IDENTIFIER; + pred->a_id = slang_atom_pool_atom(A->atoms, "__notRetFlag"); + pred->locals->outer_scope = oper->locals->outer_scope; + } } if (oper->children[0].type == SLANG_OPER_IDENTIFIER && @@ -3643,14 +4381,12 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) * cases such as "v.x = f();" - would help with typical vertex * transformation. */ - slang_ir_node *n; n = _slang_gen_function_call_name(A, (const char *) oper->children[1].a_id, &oper->children[1], &oper->children[0]); - return n; } else { - slang_ir_node *n, *lhs, *rhs; + slang_ir_node *lhs, *rhs; /* lhs and rhs type checking */ if (!_slang_assignment_compatible(A, @@ -3690,12 +4426,21 @@ _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper) rhs = _slang_gen_swizzle(rhs, newSwizzle); } n = new_node2(IR_COPY, lhs, rhs); - return n; } else { return NULL; } } + + if (n && pred) { + /* predicate the assignment code on __notRetFlag */ + slang_ir_node *top, *cond; + + cond = _slang_gen_operation(A, pred); + top = new_if(cond, n, NULL); + return top; + } + return n; } @@ -4048,16 +4793,14 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) case SLANG_OPER_WHILE: return _slang_gen_while(A, oper); case SLANG_OPER_BREAK: - if (!A->CurLoop) { - if (!A->UnrollLoop) - slang_info_log_error(A->log, "'break' not in loop"); + if (!current_loop_oper(A)) { + slang_info_log_error(A->log, "'break' not in loop"); return NULL; } - return new_break(A->CurLoop); + return new_break(current_loop_ir(A)); case SLANG_OPER_CONTINUE: - if (!A->CurLoop) { - if (!A->UnrollLoop) - slang_info_log_error(A->log, "'continue' not in loop"); + if (!current_loop_oper(A)) { + slang_info_log_error(A->log, "'continue' not in loop"); return NULL; } return _slang_gen_continue(A, oper); @@ -4182,6 +4925,8 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper) return _slang_gen_method_call(A, oper); case SLANG_OPER_RETURN: return _slang_gen_return(A, oper); + case SLANG_OPER_RETURN_INLINED: + return _slang_gen_return(A, oper); case SLANG_OPER_LABEL: return new_label(oper->label); case SLANG_OPER_IDENTIFIER: @@ -4303,6 +5048,8 @@ _slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var, const GLint totalSize = _slang_array_size(size, arrayLen); GLint texIndex = sampler_to_texture_index(var->type.specifier.type); + var->is_global = GL_TRUE; + /* check for sampler2D arrays */ if (texIndex == -1 && var->type.specifier._array) texIndex = sampler_to_texture_index(var->type.specifier._array->type); @@ -4601,7 +5348,9 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) assert(A->program->Parameters ); assert(A->program->Varying); assert(A->vartable); - A->CurLoop = NULL; + + A->LoopDepth = 0; + A->UseReturnFlag = GL_FALSE; A->CurFunction = fun; /* fold constant expressions, etc. */ diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index d80013ad34..ee3be55a45 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -31,6 +31,9 @@ #include "slang_compile.h" +#define MAX_LOOP_DEPTH 30 + + typedef struct slang_assemble_ctx_ { slang_atom_pool *atoms; @@ -39,11 +42,19 @@ typedef struct slang_assemble_ctx_ struct gl_sl_pragmas *pragmas; slang_var_table *vartable; slang_info_log *log; - struct slang_label_ *curFuncEndLabel; - struct slang_ir_node_ *CurLoop; + + /* current loop stack */ + const slang_operation *LoopOperStack[MAX_LOOP_DEPTH]; + struct slang_ir_node_ *LoopIRStack[MAX_LOOP_DEPTH]; + GLuint LoopDepth; + + /* current function */ struct slang_function_ *CurFunction; - GLuint UnrollLoop; + struct slang_label_ *curFuncEndLabel; + GLboolean UseReturnFlag; + GLboolean UnresolvedRefs; + GLboolean EmitContReturn; } slang_assemble_ctx; diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index d7ad879e97..c1b97c7cb7 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -1953,6 +1953,7 @@ static int parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, const slang_fully_specified_type * type) { + GET_CURRENT_CONTEXT(ctx); /* a hack */ slang_variable *var; slang_atom a_name; @@ -2066,6 +2067,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, A.vartable = O->vartable; A.log = C->L; A.curFuncEndLabel = NULL; + A.EmitContReturn = ctx->Shader.EmitContReturn; if (!_slang_codegen_global_variable(&A, var, C->type)) RETURN0; } @@ -2430,6 +2432,7 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, A.program = o.program; A.pragmas = &shader->Pragmas; A.vartable = o.vartable; + A.EmitContReturn = ctx->Shader.EmitContReturn; A.log = C->L; /* main() takes no parameters */ diff --git a/src/mesa/shader/slang/slang_compile_operation.c b/src/mesa/shader/slang/slang_compile_operation.c index e650616880..3e2bdbc91f 100644 --- a/src/mesa/shader/slang/slang_compile_operation.c +++ b/src/mesa/shader/slang/slang_compile_operation.c @@ -119,11 +119,13 @@ slang_operation_copy(slang_operation * x, const slang_operation * y) if (!slang_operation_construct(&z)) return GL_FALSE; z.type = y->type; - z.children = (slang_operation *) - _slang_alloc(y->num_children * sizeof(slang_operation)); - if (z.children == NULL) { - slang_operation_destruct(&z); - return GL_FALSE; + if (y->num_children > 0) { + z.children = (slang_operation *) + _slang_alloc(y->num_children * sizeof(slang_operation)); + if (z.children == NULL) { + slang_operation_destruct(&z); + return GL_FALSE; + } } for (z.num_children = 0; z.num_children < y->num_children; z.num_children++) { @@ -152,6 +154,15 @@ slang_operation_copy(slang_operation * x, const slang_operation * y) return GL_FALSE; } } + + /* update scoping for children */ + for (i = 0; i < y->num_children; i++) { + if (y->children[i].locals && + y->children[i].locals->outer_scope == y->locals) { + z.children[i].locals->outer_scope = z.locals; + } + } + #if 0 z.var = y->var; z.fun = y->fun; @@ -198,6 +209,20 @@ slang_operation_delete(slang_operation *oper) } +void +slang_operation_free_children(slang_operation *oper) +{ + GLuint i; + for (i = 0; i < slang_oper_num_children(oper); i++) { + slang_operation *child = slang_oper_child(oper, i); + slang_operation_destruct(child); + } + _slang_free(oper->children); + oper->children = NULL; + oper->num_children = 0; +} + + slang_operation * slang_operation_grow(GLuint *numChildren, slang_operation **children) { @@ -263,6 +288,26 @@ slang_operation_insert(GLuint *numElements, slang_operation **array, } +/** + * Add/insert new child into given node at given position. + * \return pointer to the new child node + */ +slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos) +{ + slang_operation *newOp; + + newOp = slang_operation_insert(&oper->num_children, + &oper->children, + pos); + if (newOp) { + newOp->locals->outer_scope = oper->locals; + } + + return newOp; +} + + void _slang_operation_swap(slang_operation *oper0, slang_operation *oper1) { @@ -272,3 +317,16 @@ _slang_operation_swap(slang_operation *oper0, slang_operation *oper1) } +void +slang_operation_add_children(slang_operation *oper, GLuint num_children) +{ + GLuint i; + assert(oper->num_children == 0); + assert(oper->children == NULL); + oper->num_children = num_children; + oper->children = slang_operation_new(num_children); + for (i = 0; i < num_children; i++) { + oper->children[i].locals = _slang_variable_scope_new(oper->locals); + } +} + diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index 37af5d617c..58f1edeed8 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -42,6 +42,7 @@ typedef enum slang_operation_type_ SLANG_OPER_CONTINUE, /* "continue" statement */ SLANG_OPER_DISCARD, /* "discard" (kill fragment) statement */ SLANG_OPER_RETURN, /* "return" [expr] */ + SLANG_OPER_RETURN_INLINED, /* "return" [expr] from inlined function */ SLANG_OPER_LABEL, /* a jump target */ SLANG_OPER_EXPRESSION, /* [expr] */ SLANG_OPER_IF, /* "if" [0] then [1] else [2] */ @@ -150,6 +151,9 @@ slang_operation_new(GLuint count); extern void slang_operation_delete(slang_operation *oper); +extern void +slang_operation_free_children(slang_operation *oper); + extern slang_operation * slang_operation_grow(GLuint *numChildren, slang_operation **children); @@ -157,8 +161,66 @@ extern slang_operation * slang_operation_insert(GLuint *numChildren, slang_operation **children, GLuint pos); +extern slang_operation * +slang_operation_insert_child(slang_operation *oper, GLuint pos); + extern void _slang_operation_swap(slang_operation *oper0, slang_operation *oper1); +extern void +slang_operation_add_children(slang_operation *oper, GLuint num_children); + + +/** Return number of children of given node */ +static INLINE GLuint +slang_oper_num_children(const slang_operation *oper) +{ + return oper->num_children; +} + +/** Return child of given operation node */ +static INLINE slang_operation * +slang_oper_child(slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + +/** Return child of given operation node, const version */ +static INLINE const slang_operation * +slang_oper_child_const(const slang_operation *oper, GLuint child) +{ + assert(child < oper->num_children); + return &oper->children[child]; +} + + +/** Init oper to a boolean literal. */ +static INLINE void +slang_operation_literal_bool(slang_operation *oper, GLboolean value) +{ + oper->type = SLANG_OPER_LITERAL_BOOL; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + +/** Init oper to an int literal. */ +static INLINE void +slang_operation_literal_int(slang_operation *oper, GLint value) +{ + oper->type = SLANG_OPER_LITERAL_INT; + oper->literal[0] = + oper->literal[1] = + oper->literal[2] = + oper->literal[3] = (float) value; + oper->literal_size = 1; +} + + #endif /* SLANG_COMPILE_OPERATION_H */ diff --git a/src/mesa/shader/slang/slang_compile_variable.h b/src/mesa/shader/slang/slang_compile_variable.h index a667d91b47..b4585599f2 100644 --- a/src/mesa/shader/slang/slang_compile_variable.h +++ b/src/mesa/shader/slang/slang_compile_variable.h @@ -39,6 +39,7 @@ typedef struct slang_variable_ GLuint array_len; /**< only if type == SLANG_SPEC_ARRAy */ struct slang_operation_ *initializer; /**< Optional initializer code */ GLuint size; /**< Variable's size in bytes */ + GLboolean is_global; GLboolean isTemp; /**< a named temporary (__resultTmp) */ GLboolean declared; /**< for debug */ struct slang_ir_storage_ *store; /**< Storage for this var */ diff --git a/src/mesa/shader/slang/slang_print.c b/src/mesa/shader/slang/slang_print.c index bf1475f91d..98c7877534 100644 --- a/src/mesa/shader/slang/slang_print.c +++ b/src/mesa/shader/slang/slang_print.c @@ -261,6 +261,7 @@ slang_print_tree(const slang_operation *op, int indent) break; case SLANG_OPER_BLOCK_NEW_SCOPE: + case SLANG_OPER_NON_INLINED_CALL: spaces(indent); printf("{{ // new scope locals=%p outer=%p: ", (void *) op->locals, @@ -348,6 +349,13 @@ slang_print_tree(const slang_operation *op, int indent) slang_print_tree(&op->children[0], indent + 3); break; + case SLANG_OPER_RETURN_INLINED: + spaces(indent); + printf("RETURN_INLINED\n"); + if (op->num_children > 0) + slang_print_tree(&op->children[0], indent + 3); + break; + case SLANG_OPER_LABEL: spaces(indent); printf("LABEL %s\n", (char *) op->a_id); @@ -478,7 +486,7 @@ slang_print_tree(const slang_operation *op, int indent) (void *) scope, (void *) op->locals, (void *) op->locals->outer_scope); - assert(scope); + /*assert(scope);*/ } } break; diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index 92ddffc014..8514b6b375 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -274,20 +274,11 @@ st_make_current(struct st_context *st, _glapi_check_multithread(); if (st) { - GLboolean firstTime = st->ctx->FirstTimeCurrent; - if(!_mesa_make_current(st->ctx, &draw->Base, &read->Base)) + if (!_mesa_make_current(st->ctx, &draw->Base, &read->Base)) return GL_FALSE; - /* Need to initialize viewport here since draw->Base->Width/Height - * will still be zero at this point. - * This could be improved, but would require rather extensive work - * elsewhere (allocate rb surface storage sooner) - */ - if (firstTime) { - GLuint w = draw->InitWidth, h = draw->InitHeight; - _mesa_set_viewport(st->ctx, 0, 0, w, h); - _mesa_set_scissor(st->ctx, 0, 0, w, h); - } + _mesa_check_init_viewport(st->ctx, draw->InitWidth, draw->InitHeight); + return GL_TRUE; } else { diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index 8e036223c6..914a507bef 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -229,8 +229,10 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count, struct st_buffer_object *stobj = st_buffer_object(array->BufferObj); ubyte *map; - if (!stobj) + if (!stobj || stobj->Base.Name == 0) { + /* edge flags are not in a VBO */ return NULL; + } vec = (unsigned *) _mesa_calloc(sizeof(unsigned) * ((count + 31) / 32)); if (!vec) diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index ab83543063..a35eab03e7 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -120,6 +120,11 @@ void st_init_limits(struct st_context *st) c->MaxDrawBuffers = CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), 1, MAX_DRAW_BUFFERS); + + /* Is TGSI_OPCODE_CONT supported? */ + /* XXX separate query for early function return? */ + st->ctx->Shader.EmitContReturn = + screen->get_param(screen, PIPE_CAP_TGSI_CONT_SUPPORTED); } diff --git a/src/mesa/state_tracker/st_framebuffer.c b/src/mesa/state_tracker/st_framebuffer.c index 7072cbe62c..13589151ba 100644 --- a/src/mesa/state_tracker/st_framebuffer.c +++ b/src/mesa/state_tracker/st_framebuffer.c @@ -134,16 +134,7 @@ void st_resize_framebuffer( struct st_framebuffer *stfb, if (stfb->Base.Width != width || stfb->Base.Height != height) { GET_CURRENT_CONTEXT(ctx); if (ctx) { - if (stfb->InitWidth == 0 && stfb->InitHeight == 0) { - /* didn't have a valid size until now */ - stfb->InitWidth = width; - stfb->InitHeight = height; - if (ctx->Viewport.Width <= 1) { - /* set context's initial viewport/scissor size */ - _mesa_set_viewport(ctx, 0, 0, width, height); - _mesa_set_scissor(ctx, 0, 0, width, height); - } - } + _mesa_check_init_viewport(ctx, width, height); _mesa_resize_framebuffer(ctx, &stfb->Base, width, height); diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c index dc6d77825f..58f6933652 100644 --- a/src/mesa/state_tracker/st_gen_mipmap.c +++ b/src/mesa/state_tracker/st_gen_mipmap.c @@ -198,9 +198,6 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, return; } - if (dstImage->ImageOffsets) - _mesa_free(dstImage->ImageOffsets); - /* Free old image data */ if (dstImage->Data) ctx->Driver.FreeTexImageData(ctx, dstImage); diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c index 868226075a..3c4c8acc63 100644 --- a/src/mesa/vbo/vbo_save_api.c +++ b/src/mesa/vbo/vbo_save_api.c @@ -1139,21 +1139,21 @@ static void vbo_print_vertex_list( GLcontext *ctx, void *data ) GLuint i; (void) ctx; - _mesa_debug(NULL, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", - node->count, - node->prim_count, - node->vertex_size); + _mesa_printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", + node->count, + node->prim_count, + node->vertex_size); for (i = 0 ; i < node->prim_count ; i++) { struct _mesa_prim *prim = &node->prim[i]; - _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n", - i, - _mesa_lookup_enum_by_nr(prim->mode), - prim->weak ? " (weak)" : "", - prim->start, - prim->start + prim->count, - (prim->begin) ? "BEGIN" : "(wrap)", - (prim->end) ? "END" : "(wrap)"); + _mesa_printf(" prim %d: %s%s %d..%d %s %s\n", + i, + _mesa_lookup_enum_by_nr(prim->mode), + prim->weak ? " (weak)" : "", + prim->start, + prim->start + prim->count, + (prim->begin) ? "BEGIN" : "(wrap)", + (prim->end) ? "END" : "(wrap)"); } } |