*fence = NULL;
}
+
+/**
+ * Flush context if necessary.
+ *
+ * Returns FALSE if it would have block, but do_not_block was set, TRUE
+ * otherwise.
+ *
+ * TODO: move this logic to an auxiliary library?
+ */
+boolean
+softpipe_flush_resource(struct pipe_context *pipe,
+ struct pipe_resource *texture,
+ unsigned face,
+ unsigned level,
+ unsigned flush_flags,
+ boolean read_only,
+ boolean cpu_access,
+ boolean do_not_block)
+{
+ unsigned referenced;
+
+ referenced = pipe->is_resource_referenced(pipe, texture, face, level);
+
+ if ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
+ ((referenced & PIPE_REFERENCED_FOR_READ) && !read_only)) {
+
+ /*
+ * TODO: The semantics of these flush flags are too obtuse. They should
+ * disappear and the pipe driver should just ensure that all visible
+ * side-effects happen when they need to happen.
+ */
+ if (referenced & PIPE_REFERENCED_FOR_WRITE)
+ flush_flags |= PIPE_FLUSH_RENDER_CACHE;
+
+ if (referenced & PIPE_REFERENCED_FOR_READ)
+ flush_flags |= PIPE_FLUSH_TEXTURE_CACHE;
+
+ if (cpu_access) {
+ /*
+ * Flush and wait.
+ */
+
+ struct pipe_fence_handle *fence = NULL;
+
+ if (do_not_block)
+ return FALSE;
+
+ pipe->flush(pipe, flush_flags, &fence);
+
+ if (fence) {
+ /*
+ * This is for illustrative purposes only, as softpipe does not
+ * have fences.
+ */
+ pipe->screen->fence_finish(pipe->screen, fence, 0);
+ pipe->screen->fence_reference(pipe->screen, &fence, NULL);
+ }
+ } else {
+ /*
+ * Just flush.
+ */
+
+ pipe->flush(pipe, flush_flags, NULL);
+ }
+ }
+
+ return TRUE;
+}
#ifndef SP_FLUSH_H
#define SP_FLUSH_H
+#include "pipe/p_compiler.h"
+
struct pipe_context;
struct pipe_fence_handle;
-void softpipe_flush(struct pipe_context *pipe, unsigned flags,
- struct pipe_fence_handle **fence);
+void
+softpipe_flush(struct pipe_context *pipe, unsigned flags,
+ struct pipe_fence_handle **fence);
+
+boolean
+softpipe_flush_resource(struct pipe_context *pipe,
+ struct pipe_resource *texture,
+ unsigned face,
+ unsigned level,
+ unsigned flush_flags,
+ boolean read_only,
+ boolean cpu_access,
+ boolean do_not_block);
#endif
addr.bits.face,
addr.bits.level,
addr.bits.z,
- PIPE_TRANSFER_READ, 0, 0,
+ PIPE_TRANSFER_READ | PIPE_TRANSFER_UNSYNCHRONIZED,
+ 0, 0,
u_minify(tc->texture->width0, addr.bits.level),
u_minify(tc->texture->height0, addr.bits.level));
#include "util/u_transfer.h"
#include "sp_context.h"
+#include "sp_flush.h"
#include "sp_texture.h"
#include "sp_screen.h"
assert(box->y + box->height <= u_minify(resource->height0, sr.level));
assert(box->z + box->depth <= u_minify(resource->depth0, sr.level));
+ /*
+ * Transfers, like other pipe operations, must happen in order, so flush the
+ * context if necessary.
+ */
+ if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
+ boolean read_only = !(usage & PIPE_TRANSFER_WRITE);
+ boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK);
+ if (!softpipe_flush_resource(pipe, resource,
+ sr.face, sr.level,
+ 0, /* flush_flags */
+ read_only,
+ TRUE, /* cpu_access */
+ do_not_block)) {
+ /*
+ * It would have blocked, but state tracker requested no to.
+ */
+ assert(do_not_block);
+ return NULL;
+ }
+ }
+
spr = CALLOC_STRUCT(softpipe_transfer);
if (spr) {
struct pipe_transfer *pt = &spr->base;
if (ps) {
tc->transfer = pipe_get_transfer(pipe, ps->texture, ps->face,
ps->level, ps->zslice,
- PIPE_TRANSFER_READ_WRITE,
+ PIPE_TRANSFER_READ_WRITE |
+ PIPE_TRANSFER_UNSYNCHRONIZED,
0, 0, ps->width, ps->height);
tc->depth_stencil = (ps->format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||