void r600_need_cs_space(struct r600_context *ctx, unsigned num_dw, boolean count_draw_in) { struct radeon_winsys_cs *dma = ctx->b.dma.cs; /* Flush the DMA IB if it's not empty. */ if (dma && dma->cdw) ctx->b.dma.flush(ctx, RADEON_FLUSH_ASYNC, NULL); if (!ctx->b.ws->cs_memory_below_limit(ctx->b.gfx.cs, ctx->b.vram, ctx->b.gtt)) { ctx->b.gtt = 0; ctx->b.vram = 0; ctx->b.gfx.flush(ctx, RADEON_FLUSH_ASYNC, NULL); return; } /* all will be accounted once relocation are emited */ ctx->b.gtt = 0; ctx->b.vram = 0; /* The number of dwords we already used in the CS so far. */ num_dw += ctx->b.gfx.cs->cdw; if (count_draw_in) { uint64_t mask; /* The number of dwords all the dirty states would take. */ mask = ctx->dirty_atoms; while (mask != 0) { num_dw += ctx->atoms[u_bit_scan64(&mask)]->num_dw; if (ctx->screen->b.trace_bo) { num_dw += R600_TRACE_CS_DWORDS; } } /* The upper-bound of how much space a draw command would take. */ num_dw += R600_MAX_FLUSH_CS_DWORDS + R600_MAX_DRAW_CS_DWORDS; if (ctx->screen->b.trace_bo) { num_dw += R600_TRACE_CS_DWORDS; } } /* Count in queries_suspend. */ num_dw += ctx->b.num_cs_dw_nontimer_queries_suspend + ctx->b.num_cs_dw_timer_queries_suspend; /* Count in streamout_end at the end of CS. */ if (ctx->b.streamout.begin_emitted) { num_dw += ctx->b.streamout.num_dw_for_end; } /* SX_MISC */ if (ctx->b.chip_class == R600) { num_dw += 3; } /* Count in framebuffer cache flushes at the end of CS. */ num_dw += R600_MAX_FLUSH_CS_DWORDS; /* The fence at the end of CS. */ num_dw += 10; /* Flush if there's not enough space. */ if (num_dw > ctx->b.gfx.cs->max_dw) { ctx->b.gfx.flush(ctx, RADEON_FLUSH_ASYNC, NULL); } }
/** * Copy the active vertex's values to the ctx->Current fields. */ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) { struct gl_context *ctx = exec->ctx; struct vbo_context *vbo = vbo_context(ctx); GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); while (enabled) { const int i = u_bit_scan64(&enabled); /* Note: the exec->vtx.current[i] pointers point into the * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. */ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; fi_type tmp[8]; /* space for doubles */ int dmul = exec->vtx.attrtype[i] == GL_DOUBLE ? 2 : 1; assert(exec->vtx.attrsz[i]); if (exec->vtx.attrtype[i] == GL_DOUBLE) { memset(tmp, 0, sizeof(tmp)); memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attrsz[i] * sizeof(GLfloat)); } else { COPY_CLEAN_4V_TYPE_AS_UNION(tmp, exec->vtx.attrsz[i], exec->vtx.attrptr[i], exec->vtx.attrtype[i]); } if (exec->vtx.attrtype[i] != vbo->currval[i].Type || memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) { memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul); /* Given that we explicitly state size here, there is no need * for the COPY_CLEAN above, could just copy 16 bytes and be * done. The only problem is when Mesa accesses ctx->Current * directly. */ /* Size here is in components - not bytes */ vbo->currval[i].Size = exec->vtx.attrsz[i] / dmul; vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat) * dmul; vbo->currval[i].Type = exec->vtx.attrtype[i]; vbo->currval[i].Integer = vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]); vbo->currval[i].Doubles = vbo_attrtype_to_double_flag(exec->vtx.attrtype[i]); /* This triggers rather too much recalculation of Mesa state * that doesn't get used (eg light positions). */ if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && i <= VBO_ATTRIB_MAT_BACK_INDEXES) ctx->NewState |= _NEW_LIGHT; ctx->NewState |= _NEW_CURRENT_ATTRIB; } } /* Colormaterial -- this kindof sucks. */ if (ctx->Light.ColorMaterialEnabled && exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) { _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); } }
/** * Flush existing data, set new attrib size, replay copied vertices. * This is called when we transition from a small vertex attribute size * to a larger one. Ex: glTexCoord2f -> glTexCoord4f. * We need to go back over the previous 2-component texcoords and insert * zero and one values. */ static void vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, GLuint attr, GLuint newSize ) { struct gl_context *ctx = exec->ctx; struct vbo_context *vbo = vbo_context(ctx); const GLint lastcount = exec->vtx.vert_count; fi_type *old_attrptr[VBO_ATTRIB_MAX]; const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */ const GLuint oldSize = exec->vtx.attrsz[attr]; GLuint i; /* Run pipeline on current vertices, copy wrapped vertices * to exec->vtx.copied. */ vbo_exec_wrap_buffers( exec ); if (unlikely(exec->vtx.copied.nr)) { /* We're in the middle of a primitive, keep the old vertex * format around to be able to translate the copied vertices to * the new format. */ memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr)); } if (unlikely(oldSize)) { /* Do a COPY_TO_CURRENT to ensure back-copying works for the * case when the attribute already exists in the vertex and is * having its size increased. */ vbo_exec_copy_to_current( exec ); } /* Heuristic: Attempt to isolate attributes received outside * begin/end so that they don't bloat the vertices. */ if (!_mesa_inside_begin_end(ctx) && !oldSize && lastcount > 8 && exec->vtx.vertex_size) { vbo_exec_copy_to_current( exec ); reset_attrfv( exec ); } /* Fix up sizes: */ exec->vtx.attrsz[attr] = newSize; exec->vtx.vertex_size += newSize - oldSize; exec->vtx.max_vert = vbo_compute_max_verts(exec); exec->vtx.vert_count = 0; exec->vtx.buffer_ptr = exec->vtx.buffer_map; exec->vtx.enabled |= BITFIELD64_BIT(attr); if (unlikely(oldSize)) { /* Size changed, recalculate all the attrptr[] values */ fi_type *tmp = exec->vtx.vertex; for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { if (exec->vtx.attrsz[i]) { exec->vtx.attrptr[i] = tmp; tmp += exec->vtx.attrsz[i]; } else exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */ } /* Copy from current to repopulate the vertex with correct * values. */ vbo_exec_copy_from_current( exec ); } else { /* Just have to append the new attribute at the end */ exec->vtx.attrptr[attr] = exec->vtx.vertex + exec->vtx.vertex_size - newSize; } /* Replay stored vertices to translate them * to new format here. * * -- No need to replay - just copy piecewise */ if (unlikely(exec->vtx.copied.nr)) { fi_type *data = exec->vtx.copied.buffer; fi_type *dest = exec->vtx.buffer_ptr; assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map); for (i = 0 ; i < exec->vtx.copied.nr ; i++) { GLbitfield64 enabled = exec->vtx.enabled; while (enabled) { const int j = u_bit_scan64(&enabled); GLuint sz = exec->vtx.attrsz[j]; GLint old_offset = old_attrptr[j] - exec->vtx.vertex; GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex; assert(sz); if (j == attr) { if (oldSize) { fi_type tmp[4]; COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize, data + old_offset, exec->vtx.attrtype[j]); COPY_SZ_4V(dest + new_offset, newSize, tmp); } else { fi_type *current = (fi_type *)vbo->currval[j].Ptr; COPY_SZ_4V(dest + new_offset, sz, current); } } else { COPY_SZ_4V(dest + new_offset, sz, data + old_offset); } } data += old_vtx_size; dest += exec->vtx.vertex_size; } exec->vtx.buffer_ptr = dest; exec->vtx.vert_count += exec->vtx.copied.nr; exec->vtx.copied.nr = 0; } }
/** * After playback, copy everything but the position from the * last vertex to the saved state */ static void _playback_copy_to_current(struct gl_context *ctx, const struct vbo_save_vertex_list *node) { struct vbo_context *vbo = vbo_context(ctx); fi_type vertex[VBO_ATTRIB_MAX * 4]; fi_type *data; GLbitfield64 mask; GLuint offset; if (node->current_size == 0) return; if (node->current_data) { data = node->current_data; } else { data = vertex; if (node->count) offset = (node->buffer_offset + (node->count-1) * node->vertex_size * sizeof(GLfloat)); else offset = node->buffer_offset; ctx->Driver.GetBufferSubData( ctx, offset, node->vertex_size * sizeof(GLfloat), data, node->vertex_store->bufferobj ); data += node->attrsz[0]; /* skip vertex position */ } mask = node->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); while (mask) { const int i = u_bit_scan64(&mask); fi_type *current = (fi_type *)vbo->currval[i].Ptr; fi_type tmp[4]; assert(node->attrsz[i]); COPY_CLEAN_4V_TYPE_AS_UNION(tmp, node->attrsz[i], data, node->attrtype[i]); if (node->attrtype[i] != vbo->currval[i].Type || memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) { memcpy(current, tmp, 4 * sizeof(GLfloat)); vbo->currval[i].Size = node->attrsz[i]; vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); vbo->currval[i].Type = node->attrtype[i]; vbo->currval[i].Integer = vbo_attrtype_to_integer_flag(node->attrtype[i]); if (i >= VBO_ATTRIB_FIRST_MATERIAL && i <= VBO_ATTRIB_LAST_MATERIAL) ctx->NewState |= _NEW_LIGHT; ctx->NewState |= _NEW_CURRENT_ATTRIB; } data += node->attrsz[i]; } /* Colormaterial -- this kindof sucks. */ if (ctx->Light.ColorMaterialEnabled) { _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); } /* CurrentExecPrimitive */ if (node->prim_count) { const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; if (prim->end) ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; else ctx->Driver.CurrentExecPrimitive = prim->mode; } }