**********************************************************/
+#include "util/u_draw.h"
+#include "util/format/u_format.h"
#include "util/u_helpers.h"
#include "util/u_inlines.h"
#include "util/u_prim.h"
#include "util/u_prim_restart.h"
#include "svga_context.h"
+#include "svga_draw_private.h"
+#include "svga_screen.h"
#include "svga_draw.h"
#include "svga_shader.h"
#include "svga_surface.h"
#include "svga_debug.h"
#include "svga_resource_buffer.h"
-/* Returns TRUE if we are currently using flat shading.
- */
-static boolean
-is_using_flat_shading(const struct svga_context *svga)
-{
- return
- svga->state.hw_draw.fs ? svga->state.hw_draw.fs->uses_flat_interp : FALSE;
-}
-
static enum pipe_error
retry_draw_range_elements(struct svga_context *svga,
const struct pipe_draw_info *info,
unsigned count)
{
- enum pipe_error ret;
-
SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWELEMENTS);
- ret = svga_hwtnl_draw_range_elements(svga->hwtnl, info, count);
- if (ret != PIPE_OK) {
- svga_context_flush(svga, NULL);
- ret = svga_hwtnl_draw_range_elements(svga->hwtnl, info, count);
- }
+ SVGA_RETRY(svga, svga_hwtnl_draw_range_elements(svga->hwtnl, info, count));
- assert (ret == PIPE_OK);
SVGA_STATS_TIME_POP(svga_sws(svga));
- return ret;
+ return PIPE_OK;
}
static enum pipe_error
-retry_draw_arrays(struct svga_context *svga,
- enum pipe_prim_type prim, unsigned start, unsigned count,
- unsigned start_instance, unsigned instance_count)
+retry_draw_arrays( struct svga_context *svga,
+ enum pipe_prim_type prim, unsigned start, unsigned count,
+ unsigned start_instance, unsigned instance_count,
+ ubyte vertices_per_patch)
{
enum pipe_error ret;
SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWARRAYS);
- for (unsigned try = 0; try < 2; try++) {
- ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count,
- start_instance, instance_count);
- if (ret == PIPE_OK)
- break;
- svga_context_flush(svga, NULL);
- }
-
+ SVGA_RETRY_OOM(svga, ret, svga_hwtnl_draw_arrays(svga->hwtnl, prim, start,
+ count, start_instance,
+ instance_count,
+ vertices_per_patch));
SVGA_STATS_TIME_POP(svga_sws(svga));
return ret;
}
+/**
+ * Auto draw (get vertex count from a transform feedback result).
+ */
+static enum pipe_error
+retry_draw_auto(struct svga_context *svga,
+ const struct pipe_draw_info *info)
+{
+ assert(svga_have_sm5(svga));
+ assert(info->count_from_stream_output);
+ assert(info->instance_count == 1);
+ /* SO drawing implies core profile and none of these prim types */
+ assert(info->mode != PIPE_PRIM_QUADS &&
+ info->mode != PIPE_PRIM_QUAD_STRIP &&
+ info->mode != PIPE_PRIM_POLYGON);
+
+ if (info->mode == PIPE_PRIM_LINE_LOOP) {
+ /* XXX need to do a fallback */
+ assert(!"draw auto fallback not supported yet");
+ return PIPE_OK;
+ }
+ else {
+ SVGA3dPrimitiveRange range;
+ unsigned hw_count;
+
+ range.primType = svga_translate_prim(info->mode, 12, &hw_count,
+ info->vertices_per_patch);
+ range.primitiveCount = 0;
+ range.indexArray.surfaceId = SVGA3D_INVALID_ID;
+ range.indexArray.offset = 0;
+ range.indexArray.stride = 0;
+ range.indexWidth = 0;
+ range.indexBias = 0;
+
+ SVGA_RETRY(svga, svga_hwtnl_prim
+ (svga->hwtnl, &range,
+ 0, /* vertex count comes from SO buffer */
+ 0, /* don't know min index */
+ ~0u, /* don't know max index */
+ NULL, /* no index buffer */
+ 0, /* start instance */
+ 1, /* only 1 instance supported */
+ NULL, /* indirect drawing info */
+ info->count_from_stream_output));
+
+ return PIPE_OK;
+ }
+}
+
+
+/**
+ * Indirect draw (get vertex count, start index, etc. from a buffer object.
+ */
+static enum pipe_error
+retry_draw_indirect(struct svga_context *svga,
+ const struct pipe_draw_info *info)
+{
+ assert(svga_have_sm5(svga));
+ assert(info->indirect);
+ /* indirect drawing implies core profile and none of these prim types */
+ assert(info->mode != PIPE_PRIM_QUADS &&
+ info->mode != PIPE_PRIM_QUAD_STRIP &&
+ info->mode != PIPE_PRIM_POLYGON);
+
+ if (info->mode == PIPE_PRIM_LINE_LOOP) {
+ /* need to do a fallback */
+ util_draw_indirect(&svga->pipe, info);
+ return PIPE_OK;
+ }
+ else {
+ SVGA3dPrimitiveRange range;
+ unsigned hw_count;
+
+ range.primType = svga_translate_prim(info->mode, 12, &hw_count,
+ info->vertices_per_patch);
+ range.primitiveCount = 0; /* specified in indirect buffer */
+ range.indexArray.surfaceId = SVGA3D_INVALID_ID;
+ range.indexArray.offset = 0;
+ range.indexArray.stride = 0;
+ range.indexWidth = info->index_size;
+ range.indexBias = 0; /* specified in indirect buffer */
+
+ SVGA_RETRY(svga, svga_hwtnl_prim
+ (svga->hwtnl, &range,
+ 0, /* vertex count is in indirect buffer */
+ 0, /* don't know min index */
+ ~0u, /* don't know max index */
+ info->index.resource,
+ info->start_instance,
+ 0, /* don't know instance count */
+ info->indirect,
+ NULL)); /* SO vertex count */
+
+ return PIPE_OK;
+ }
+}
+
+
/**
* Determine if we need to implement primitive restart with a fallback
* path which breaks the original primitive into sub-primitive at the
}
+/**
+ * A helper function to return the vertex count from the primitive count
+ * returned from the stream output statistics query for the specified stream.
+ */
+static unsigned
+get_vcount_from_stream_output(struct svga_context *svga,
+ const struct pipe_draw_info *info,
+ unsigned stream)
+{
+ unsigned primcount;
+ primcount = svga_get_primcount_from_stream_output(svga, stream);
+ return u_vertices_for_prims(info->mode, primcount);
+}
+
+
static void
svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
{
svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
}
+ if (svga->curr.vertices_per_patch != info->vertices_per_patch) {
+ svga->curr.vertices_per_patch = info->vertices_per_patch;
+
+ /* If input patch size changes, we need to notifiy the TCS
+ * code to reevaluate the shader variant since the
+ * vertices per patch count is a constant in the control
+ * point count declaration.
+ */
+ if (svga->curr.tcs || svga->curr.tes)
+ svga->dirty |= SVGA_NEW_TCS_PARAM;
+ }
+
if (need_fallback_prim_restart(svga, info)) {
enum pipe_error r;
r = util_draw_vbo_without_prim_restart(pipe, info);
goto done;
}
- if (!u_trim_pipe_prim(info->mode, &count))
+ if (!info->indirect && !info->count_from_stream_output &&
+ !u_trim_pipe_prim(info->mode, &count))
goto done;
needed_swtnl = svga->state.sw.need_swtnl;
}
svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
+ svga_update_state_retry(svga, SVGA_STATE_HW_DRAW);
+
/** determine if flatshade is to be used after svga_update_state()
* in case the fragment shader is changed.
*/
svga_hwtnl_set_flatshade(svga->hwtnl,
svga->curr.rast->templ.flatshade ||
- is_using_flat_shading(svga),
+ svga_is_using_flat_shading(svga),
svga->curr.rast->templ.flatshade_first);
- if (info->index_size) {
+ if (info->count_from_stream_output) {
+ unsigned stream = 0;
+ assert(count == 0);
+
+ /* If the vertex count is from the stream output of a non-zero stream
+ * or the draw info specifies instancing, we will need a workaround
+ * since the draw_auto command does not support stream instancing.
+ * The workaround requires querying the vertex count from the
+ * stream output statistics query for the specified stream and then
+ * fallback to the regular draw function.
+ */
+
+ /* Check the stream index of the specified stream output target */
+ for (unsigned i = 0; i < ARRAY_SIZE(svga->so_targets); i++) {
+ if (svga->vcount_so_targets[i] == info->count_from_stream_output) {
+ stream = (svga->vcount_buffer_stream >> (i * 4)) & 0xf;
+ break;
+ }
+ }
+ if (info->instance_count > 1 || stream > 0) {
+ count = get_vcount_from_stream_output(svga, info, stream);
+ }
+ }
+
+ if (info->count_from_stream_output && count == 0) {
+ ret = retry_draw_auto(svga, info);
+ }
+ else if (info->indirect) {
+ ret = retry_draw_indirect(svga, info);
+ }
+ else if (info->index_size) {
ret = retry_draw_range_elements(svga, info, count);
}
else {
ret = retry_draw_arrays(svga, info->mode, info->start, count,
- info->start_instance, info->instance_count);
+ info->start_instance, info->instance_count,
+ info->vertices_per_patch);
}
}