renderer: overhaul transfer code a bit

This merges the error/bounds checking on the transfer
code, but keeps the same API, it also uses a struct
to pass through the transfer info.

this also passes a return value out to make testing easier.
macos/master
Dave Airlie 10 years ago
parent fe4d670752
commit 83d7fbb0d7
  1. 38
      src/virglrenderer.c
  2. 20
      src/virglrenderer.h
  3. 391
      src/vrend_renderer.c
  4. 30
      src/vrend_renderer.h

@ -77,7 +77,7 @@ void virgl_renderer_submit_cmd(void *buffer,
vrend_decode_block(ctx_id, buffer, ndw); vrend_decode_block(ctx_id, buffer, ndw);
} }
void virgl_renderer_transfer_write_iov(uint32_t handle, int virgl_renderer_transfer_write_iov(uint32_t handle,
uint32_t ctx_id, uint32_t ctx_id,
int level, int level,
uint32_t stride, uint32_t stride,
@ -87,21 +87,41 @@ void virgl_renderer_transfer_write_iov(uint32_t handle,
struct iovec *iovec, struct iovec *iovec,
unsigned int iovec_cnt) unsigned int iovec_cnt)
{ {
vrend_renderer_transfer_write_iov(handle, ctx_id, level, struct vrend_transfer_info transfer_info;
stride, layer_stride, (struct pipe_box *)box,
offset, iovec, iovec_cnt); transfer_info.handle = handle;
transfer_info.ctx_id = ctx_id;
transfer_info.level = level;
transfer_info.stride = stride;
transfer_info.layer_stride = layer_stride;
transfer_info.box = (struct pipe_box *)box;
transfer_info.offset = offset;
transfer_info.iovec = iovec;
transfer_info.iovec_cnt = iovec_cnt;
return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_WRITE);
} }
void virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id, int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id,
uint32_t level, uint32_t stride, uint32_t level, uint32_t stride,
uint32_t layer_stride, uint32_t layer_stride,
struct virgl_box *box, struct virgl_box *box,
uint64_t offset, struct iovec *iov, uint64_t offset, struct iovec *iovec,
int iovec_cnt) int iovec_cnt)
{ {
vrend_renderer_transfer_send_iov(handle, ctx_id, level, stride, struct vrend_transfer_info transfer_info;
layer_stride, (struct pipe_box *)box,
offset, iov, iovec_cnt); transfer_info.handle = handle;
transfer_info.ctx_id = ctx_id;
transfer_info.level = level;
transfer_info.stride = stride;
transfer_info.layer_stride = layer_stride;
transfer_info.box = (struct pipe_box *)box;
transfer_info.offset = offset;
transfer_info.iovec = iovec;
transfer_info.iovec_cnt = iovec_cnt;
return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_READ);
} }
int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov, int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov,

@ -96,22 +96,22 @@ VIRGL_EXPORT void virgl_renderer_submit_cmd(void *buffer,
int ctx_id, int ctx_id,
int ndw); int ndw);
VIRGL_EXPORT void virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id, VIRGL_EXPORT int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id,
uint32_t level, uint32_t stride, uint32_t level, uint32_t stride,
uint32_t layer_stride, uint32_t layer_stride,
struct virgl_box *box, struct virgl_box *box,
uint64_t offset, struct iovec *iov, uint64_t offset, struct iovec *iov,
int iovec_cnt); int iovec_cnt);
VIRGL_EXPORT void virgl_renderer_transfer_write_iov(uint32_t handle, VIRGL_EXPORT int virgl_renderer_transfer_write_iov(uint32_t handle,
uint32_t ctx_id, uint32_t ctx_id,
int level, int level,
uint32_t stride, uint32_t stride,
uint32_t layer_stride, uint32_t layer_stride,
struct virgl_box *box, struct virgl_box *box,
uint64_t offset, uint64_t offset,
struct iovec *iovec, struct iovec *iovec,
unsigned int iovec_cnt); unsigned int iovec_cnt);
VIRGL_EXPORT void virgl_renderer_get_cap_set(uint32_t set, uint32_t *max_ver, VIRGL_EXPORT void virgl_renderer_get_cap_set(uint32_t set, uint32_t *max_ver,
uint32_t *max_size); uint32_t *max_size);

@ -3642,53 +3642,62 @@ static void copy_transfer_data(struct pipe_resource *res,
} }
} }
void vrend_renderer_transfer_write_iov(uint32_t res_handle, static bool check_transfer_bounds(struct vrend_resource *res,
uint32_t ctx_id, uint32_t level, struct pipe_box *box)
int level, {
uint32_t stride, int lwidth, lheight;
uint32_t layer_stride, /* check mipmap level is in bounds */
struct pipe_box *box, if (level > res->base.last_level)
uint64_t offset, return false;
struct iovec *iov, /* these will catch bad y/z/w/d with 1D textures etc */
unsigned int num_iovs) lwidth = u_minify(res->base.width0, level);
{ if (box->width > lwidth)
struct vrend_resource *res; return false;
struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); if (box->x > lwidth)
void *data; return false;
if (box->width + box->x > lwidth)
if (!ctx) return false;
return;
if (ctx_id == 0)
res = vrend_resource_lookup(res_handle, ctx_id);
else
res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
if (res == NULL) { lheight = u_minify(res->base.height0, level);
struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); if (box->height > lheight)
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); return false;
return; if (box->y > lheight)
} return false;
if (box->height + box->y > lheight)
return false;
if ((res->iov && !iov) || num_iovs == 0) { if (res->base.target == PIPE_TEXTURE_3D) {
iov = res->iov; int ldepth = u_minify(res->base.depth0, level);
num_iovs = res->num_iovs; if (box->depth > ldepth)
return false;
if (box->z > ldepth)
return false;
if (box->z + box->depth > ldepth)
return false;
} else {
if (box->depth > res->base.array_size)
return false;
if (box->z > res->base.array_size)
return false;
if (box->z + box->depth > res->base.array_size)
return false;
} }
if (!box) return true;
return; }
if (!iov) { static int vrend_renderer_transfer_write_iov(struct vrend_context *ctx,
struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); struct vrend_resource *res,
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); struct iovec *iov, int num_iovs,
return; const struct vrend_transfer_info *info)
} {
void *data;
vrend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); vrend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE);
if (res->target == 0 && res->ptr) { if (res->target == 0 && res->ptr) {
vrend_read_from_iovec(iov, num_iovs, offset, res->ptr + box->x, box->width); vrend_read_from_iovec(iov, num_iovs, info->offset, res->ptr + info->box->x, info->box->width);
return; return 0;
} }
if (res->target == GL_TRANSFORM_FEEDBACK_BUFFER || if (res->target == GL_TRANSFORM_FEEDBACK_BUFFER ||
res->target == GL_ELEMENT_ARRAY_BUFFER_ARB || res->target == GL_ELEMENT_ARRAY_BUFFER_ARB ||
@ -3696,24 +3705,23 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
res->target == GL_TEXTURE_BUFFER || res->target == GL_TEXTURE_BUFFER ||
res->target == GL_UNIFORM_BUFFER) { res->target == GL_UNIFORM_BUFFER) {
struct virgl_sub_upload_data d; struct virgl_sub_upload_data d;
d.box = box; d.box = info->box;
d.target = res->target; d.target = res->target;
glBindBufferARB(res->target, res->id); glBindBufferARB(res->target, res->id);
if (use_sub_data == 1) { if (use_sub_data == 1) {
vrend_read_from_iovec_cb(iov, num_iovs, offset, box->width, &iov_buffer_upload, &d); vrend_read_from_iovec_cb(iov, num_iovs, info->offset, info->box->width, &iov_buffer_upload, &d);
} else { } else {
data = glMapBufferRange(res->target, box->x, box->width, GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_WRITE_BIT); data = glMapBufferRange(res->target, info->box->x, info->box->width, GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_WRITE_BIT);
if (data == NULL) { if (data == NULL) {
fprintf(stderr,"map failed for element buffer\n"); fprintf(stderr,"map failed for element buffer\n");
vrend_read_from_iovec_cb(iov, num_iovs, offset, box->width, &iov_buffer_upload, &d); vrend_read_from_iovec_cb(iov, num_iovs, info->offset, info->box->width, &iov_buffer_upload, &d);
} else { } else {
vrend_read_from_iovec(iov, num_iovs, offset, data, box->width); vrend_read_from_iovec(iov, num_iovs, info->offset, data, info->box->width);
glUnmapBuffer(res->target); glUnmapBuffer(res->target);
} }
} }
} else { } else {
struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id);
GLenum glformat; GLenum glformat;
GLenum gltype; GLenum gltype;
int need_temp = 0; int need_temp = 0;
@ -3723,10 +3731,11 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
bool invert = false; bool invert = false;
float depth_scale; float depth_scale;
GLuint send_size = 0; GLuint send_size = 0;
uint32_t stride = info->stride;
vrend_use_program(0); vrend_use_program(0);
if (!stride) if (!stride)
stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, level)) * elsize; stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, info->level)) * elsize;
compressed = util_format_is_compressed(res->base.format); compressed = util_format_is_compressed(res->base.format);
if (num_iovs > 1 || compressed) { if (num_iovs > 1 || compressed) {
@ -3740,15 +3749,15 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
} }
if (need_temp) { if (need_temp) {
send_size = util_format_get_nblocks(res->base.format, box->width, send_size = util_format_get_nblocks(res->base.format, info->box->width,
box->height) * elsize * box->depth; info->box->height) * elsize * info->box->depth;
data = malloc(send_size); data = malloc(send_size);
if (!data) if (!data)
return; return ENOMEM;
copy_transfer_data(&res->base, iov, num_iovs, data, stride, copy_transfer_data(&res->base, iov, num_iovs, data, stride,
box, offset, invert); info->box, info->offset, invert);
} else { } else {
data = iov[0].iov_base + offset; data = iov[0].iov_base + info->offset;
} }
if (stride && !need_temp) { if (stride && !need_temp) {
@ -3776,17 +3785,17 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
gltype = tex_conv_table[res->base.format].gltype; gltype = tex_conv_table[res->base.format].gltype;
if ((!use_core_profile) && (res->y_0_top)) { if ((!use_core_profile) && (res->y_0_top)) {
if (res->readback_fb_id == 0 || res->readback_fb_level != level) { if (res->readback_fb_id == 0 || res->readback_fb_level != info->level) {
GLuint fb_id; GLuint fb_id;
if (res->readback_fb_id) if (res->readback_fb_id)
glDeleteFramebuffers(1, &res->readback_fb_id); glDeleteFramebuffers(1, &res->readback_fb_id);
glGenFramebuffers(1, &fb_id); glGenFramebuffers(1, &fb_id);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id);
vrend_fb_bind_texture(res, 0, level, 0); vrend_fb_bind_texture(res, 0, info->level, 0);
res->readback_fb_id = fb_id; res->readback_fb_id = fb_id;
res->readback_fb_level = level; res->readback_fb_level = info->level;
} else { } else {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id);
} }
@ -3796,8 +3805,8 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
vrend_alpha_test_enable(ctx, GL_FALSE); vrend_alpha_test_enable(ctx, GL_FALSE);
vrend_stencil_test_enable(GL_FALSE); vrend_stencil_test_enable(GL_FALSE);
glPixelZoom(1.0f, res->y_0_top ? -1.0f : 1.0f); glPixelZoom(1.0f, res->y_0_top ? -1.0f : 1.0f);
glWindowPos2i(box->x, res->y_0_top ? res->base.height0 - box->y : box->y); glWindowPos2i(info->box->x, res->y_0_top ? res->base.height0 - info->box->y : info->box->y);
glDrawPixels(box->width, box->height, glformat, gltype, glDrawPixels(info->box->width, info->box->height, glformat, gltype,
data); data);
} else { } else {
uint32_t comp_size; uint32_t comp_size;
@ -3805,8 +3814,8 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
if (compressed) { if (compressed) {
glformat = tex_conv_table[res->base.format].internalformat; glformat = tex_conv_table[res->base.format].internalformat;
comp_size = util_format_get_nblocks(res->base.format, box->width, comp_size = util_format_get_nblocks(res->base.format, info->box->width,
box->height) * util_format_get_blocksize(res->base.format); info->box->height) * util_format_get_blocksize(res->base.format);
} }
if (glformat == 0) { if (glformat == 0) {
@ -3814,8 +3823,8 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
gltype = GL_UNSIGNED_BYTE; gltype = GL_UNSIGNED_BYTE;
} }
x = box->x; x = info->box->x;
y = invert ? res->base.height0 - box->y - box->height : box->y; y = invert ? res->base.height0 - info->box->y - info->box->height : info->box->y;
if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) { if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) {
/* we get values from the guest as 24-bit scaled integers /* we get values from the guest as 24-bit scaled integers
@ -3828,42 +3837,42 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
vrend_scale_depth(data, send_size, depth_scale); vrend_scale_depth(data, send_size, depth_scale);
} }
if (res->target == GL_TEXTURE_CUBE_MAP) { if (res->target == GL_TEXTURE_CUBE_MAP) {
GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + box->z; GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info->box->z;
if (compressed) { if (compressed) {
glCompressedTexSubImage2D(ctarget, level, x, y, glCompressedTexSubImage2D(ctarget, info->level, x, y,
box->width, box->height, info->box->width, info->box->height,
glformat, comp_size, data); glformat, comp_size, data);
} else { } else {
glTexSubImage2D(ctarget, level, x, y, box->width, box->height, glTexSubImage2D(ctarget, info->level, x, y, info->box->width, info->box->height,
glformat, gltype, data); glformat, gltype, data);
} }
} else if (res->target == GL_TEXTURE_3D || res->target == GL_TEXTURE_2D_ARRAY || res->target == GL_TEXTURE_CUBE_MAP_ARRAY) { } else if (res->target == GL_TEXTURE_3D || res->target == GL_TEXTURE_2D_ARRAY || res->target == GL_TEXTURE_CUBE_MAP_ARRAY) {
if (compressed) { if (compressed) {
glCompressedTexSubImage3D(res->target, level, x, y, box->z, glCompressedTexSubImage3D(res->target, info->level, x, y, info->box->z,
box->width, box->height, box->depth, info->box->width, info->box->height, info->box->depth,
glformat, comp_size, data); glformat, comp_size, data);
} else { } else {
glTexSubImage3D(res->target, level, x, y, box->z, glTexSubImage3D(res->target, info->level, x, y, info->box->z,
box->width, box->height, box->depth, info->box->width, info->box->height, info->box->depth,
glformat, gltype, data); glformat, gltype, data);
} }
} else if (res->target == GL_TEXTURE_1D) { } else if (res->target == GL_TEXTURE_1D) {
if (compressed) { if (compressed) {
glCompressedTexSubImage1D(res->target, level, box->x, glCompressedTexSubImage1D(res->target, info->level, info->box->x,
box->width, info->box->width,
glformat, comp_size, data); glformat, comp_size, data);
} else { } else {
glTexSubImage1D(res->target, level, box->x, box->width, glTexSubImage1D(res->target, info->level, info->box->x, info->box->width,
glformat, gltype, data); glformat, gltype, data);
} }
} else { } else {
if (compressed) { if (compressed) {
glCompressedTexSubImage2D(res->target, level, x, res->target == GL_TEXTURE_1D_ARRAY ? box->z : y, glCompressedTexSubImage2D(res->target, info->level, x, res->target == GL_TEXTURE_1D_ARRAY ? info->box->z : y,
box->width, box->height, info->box->width, info->box->height,
glformat, comp_size, data); glformat, comp_size, data);
} else { } else {
glTexSubImage2D(res->target, level, x, res->target == GL_TEXTURE_1D_ARRAY ? box->z : y, glTexSubImage2D(res->target, info->level, x, res->target == GL_TEXTURE_1D_ARRAY ? info->box->z : y,
box->width, box->height, info->box->width, info->box->height,
glformat, gltype, data); glformat, gltype, data);
} }
} }
@ -3879,13 +3888,13 @@ void vrend_renderer_transfer_write_iov(uint32_t res_handle,
if (need_temp) if (need_temp)
free(data); free(data);
} }
return 0;
} }
static void vrend_transfer_send_getteximage(struct vrend_resource *res, static int vrend_transfer_send_getteximage(struct vrend_context *ctx,
uint32_t level, uint32_t stride, struct vrend_resource *res,
struct pipe_box *box, uint64_t offset, struct iovec *iov, int num_iovs,
struct iovec *iov, int num_iovs) const struct vrend_transfer_info *info)
{ {
GLenum format, type; GLenum format, type;
uint32_t send_size, tex_size; uint32_t send_size, tex_size;
@ -3902,21 +3911,21 @@ static void vrend_transfer_send_getteximage(struct vrend_resource *res,
format = tex_conv_table[res->base.format].internalformat; format = tex_conv_table[res->base.format].internalformat;
if (res->target == GL_TEXTURE_3D) if (res->target == GL_TEXTURE_3D)
depth = u_minify(res->base.depth0, level); depth = u_minify(res->base.depth0, info->level);
else if (res->target == GL_TEXTURE_2D_ARRAY || res->target == GL_TEXTURE_1D_ARRAY || res->target == GL_TEXTURE_CUBE_MAP_ARRAY) else if (res->target == GL_TEXTURE_2D_ARRAY || res->target == GL_TEXTURE_1D_ARRAY || res->target == GL_TEXTURE_CUBE_MAP_ARRAY)
depth = res->base.array_size; depth = res->base.array_size;
tex_size = util_format_get_nblocks(res->base.format, u_minify(res->base.width0, level), u_minify(res->base.height0, level)) * util_format_get_blocksize(res->base.format) * depth; tex_size = util_format_get_nblocks(res->base.format, u_minify(res->base.width0, info->level), u_minify(res->base.height0, info->level)) * util_format_get_blocksize(res->base.format) * depth;
send_size = util_format_get_nblocks(res->base.format, box->width, box->height) * util_format_get_blocksize(res->base.format) * box->depth; send_size = util_format_get_nblocks(res->base.format, info->box->width, info->box->height) * util_format_get_blocksize(res->base.format) * info->box->depth;
if (box->z && res->target != GL_TEXTURE_CUBE_MAP) { if (info->box->z && res->target != GL_TEXTURE_CUBE_MAP) {
send_offset = util_format_get_nblocks(res->base.format, u_minify(res->base.width0, level), u_minify(res->base.height0, level)) * util_format_get_blocksize(res->base.format) * box->z; send_offset = util_format_get_nblocks(res->base.format, u_minify(res->base.width0, info->level), u_minify(res->base.height0, info->level)) * util_format_get_blocksize(res->base.format) * info->box->z;
} }
data = malloc(tex_size); data = malloc(tex_size);
if (!data) if (!data)
return; return ENOMEM;
switch (elsize) { switch (elsize) {
case 1: case 1:
@ -3936,34 +3945,37 @@ static void vrend_transfer_send_getteximage(struct vrend_resource *res,
glBindTexture(res->target, res->id); glBindTexture(res->target, res->id);
if (res->target == GL_TEXTURE_CUBE_MAP) { if (res->target == GL_TEXTURE_CUBE_MAP) {
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + box->z; target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info->box->z;
} else } else
target = res->target; target = res->target;
if (compressed) { if (compressed) {
if (vrend_state.have_robustness) if (vrend_state.have_robustness)
glGetnCompressedTexImageARB(target, level, tex_size, data); glGetnCompressedTexImageARB(target, info->level, tex_size, data);
else else
glGetCompressedTexImage(target, level, data); glGetCompressedTexImage(target, info->level, data);
} else { } else {
if (vrend_state.have_robustness) if (vrend_state.have_robustness)
glGetnTexImageARB(target, level, format, type, tex_size, data); glGetnTexImageARB(target, info->level, format, type, tex_size, data);
else else
glGetTexImage(target, level, format, type, data); glGetTexImage(target, info->level, format, type, data);
} }
glPixelStorei(GL_PACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4);
vrend_transfer_write_tex_return(&res->base, box, level, stride, offset, iov, num_iovs, data + send_offset, send_size, FALSE); vrend_transfer_write_tex_return(&res->base, info->box, info->level,
info->stride, info->offset, iov, num_iovs,
data + send_offset, send_size, FALSE);
free(data); free(data);
return 0;
} }
static void vrend_transfer_send_readpixels(struct vrend_resource *res, static int vrend_transfer_send_readpixels(struct vrend_context *ctx,
uint32_t level, uint32_t stride, struct vrend_resource *res,
struct pipe_box *box, uint64_t offset, struct iovec *iov, int num_iovs,
struct iovec *iov, int num_iovs) const struct vrend_transfer_info *info)
{ {
void *myptr = iov[0].iov_base + offset; void *myptr = iov[0].iov_base + info->offset;
int need_temp = 0; int need_temp = 0;
GLuint fb_id; GLuint fb_id;
void *data; void *data;
@ -3971,7 +3983,7 @@ static void vrend_transfer_send_readpixels(struct vrend_resource *res,
GLenum format, type; GLenum format, type;
GLint y1; GLint y1;
uint32_t send_size = 0; uint32_t send_size = 0;
uint32_t h = u_minify(res->base.height0, level); uint32_t h = u_minify(res->base.height0, info->level);
int elsize = util_format_get_blocksize(res->base.format); int elsize = util_format_get_blocksize(res->base.format);
float depth_scale; float depth_scale;
vrend_use_program(0); vrend_use_program(0);
@ -3988,18 +4000,18 @@ static void vrend_transfer_send_readpixels(struct vrend_resource *res,
if (num_iovs > 1 || separate_invert) if (num_iovs > 1 || separate_invert)
need_temp = 1; need_temp = 1;
send_size = box->width * box->height * box->depth * util_format_get_blocksize(res->base.format); send_size = info->box->width * info->box->height * info->box->depth * util_format_get_blocksize(res->base.format);
if (need_temp) { if (need_temp) {
data = malloc(send_size); data = malloc(send_size);
if (!data) { if (!data) {
fprintf(stderr,"malloc failed %d\n", send_size); fprintf(stderr,"malloc failed %d\n", send_size);
return; return ENOMEM;
} }
} else } else
data = myptr; data = myptr;
if (res->readback_fb_id == 0 || res->readback_fb_level != level || res->readback_fb_z != box->z) { if (res->readback_fb_id == 0 || res->readback_fb_level != info->level || res->readback_fb_z != info->box->z) {
if (res->readback_fb_id) if (res->readback_fb_id)
glDeleteFramebuffers(1, &res->readback_fb_id); glDeleteFramebuffers(1, &res->readback_fb_id);
@ -4007,24 +4019,24 @@ static void vrend_transfer_send_readpixels(struct vrend_resource *res,
glGenFramebuffers(1, &fb_id); glGenFramebuffers(1, &fb_id);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id);
vrend_fb_bind_texture(res, 0, level, box->z); vrend_fb_bind_texture(res, 0, info->level, info->box->z);
res->readback_fb_id = fb_id; res->readback_fb_id = fb_id;
res->readback_fb_level = level; res->readback_fb_level = info->level;
res->readback_fb_z = box->z; res->readback_fb_z = info->box->z;
} else } else
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id);
if (actually_invert) if (actually_invert)
y1 = h - box->y - box->height; y1 = h - info->box->y - info->box->height;
else else
y1 = box->y; y1 = info->box->y;
if (have_invert_mesa && actually_invert) if (have_invert_mesa && actually_invert)
glPixelStorei(GL_PACK_INVERT_MESA, 1); glPixelStorei(GL_PACK_INVERT_MESA, 1);
if (!vrend_format_is_ds(res->base.format)) if (!vrend_format_is_ds(res->base.format))
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
if (!need_temp && stride) if (!need_temp && info->stride)
glPixelStorei(GL_PACK_ROW_LENGTH, stride); glPixelStorei(GL_PACK_ROW_LENGTH, info->stride);
switch (elsize) { switch (elsize) {
case 1: case 1:
@ -4052,9 +4064,9 @@ static void vrend_transfer_send_readpixels(struct vrend_resource *res,
} }
} }
if (vrend_state.have_robustness) if (vrend_state.have_robustness)
glReadnPixelsARB(box->x, y1, box->width, box->height, format, type, send_size, data); glReadnPixelsARB(info->box->x, y1, info->box->width, info->box->height, format, type, send_size, data);
else else
glReadPixels(box->x, y1, box->width, box->height, format, type, data); glReadPixels(info->box->x, y1, info->box->width, info->box->height, format, type, data);
if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) { if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) {
if (!use_core_profile) if (!use_core_profile)
@ -4064,80 +4076,27 @@ static void vrend_transfer_send_readpixels(struct vrend_resource *res,
} }
if (have_invert_mesa && actually_invert) if (have_invert_mesa && actually_invert)
glPixelStorei(GL_PACK_INVERT_MESA, 0); glPixelStorei(GL_PACK_INVERT_MESA, 0);
if (!need_temp && stride) if (!need_temp && info->stride)
glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4);
if (need_temp) { if (need_temp) {
vrend_transfer_write_tex_return(&res->base, box, level, stride, offset, iov, num_iovs, data, send_size, separate_invert); vrend_transfer_write_tex_return(&res->base, info->box, info->level,
info->stride, info->offset, iov, num_iovs,
data, send_size, separate_invert);
free(data); free(data);
} }
return 0;
} }
static bool check_tsend_bounds(struct vrend_resource *res, static int vrend_renderer_transfer_send_iov(struct vrend_context *ctx,
uint32_t level, struct pipe_box *box) struct vrend_resource *res,
{ struct iovec *iov, int num_iovs,
const struct vrend_transfer_info *info)
if (box->width > u_minify(res->base.width0, level))
return false;
if (box->x > u_minify(res->base.width0, level))
return false;
if (box->width + box->x > u_minify(res->base.width0, level))
return false;
if (box->height > u_minify(res->base.height0, level))
return false;
if (box->y > u_minify(res->base.height0, level))
return false;
if (box->height + box->y > u_minify(res->base.height0, level))
return false;
/* bounds checks TODO,
box depth / box->z and array layers */
return true;
}
void vrend_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id,
uint32_t level, uint32_t stride,
uint32_t layer_stride,
struct pipe_box *box,
uint64_t offset, struct iovec *iov,
int num_iovs)
{ {
struct vrend_resource *res;
struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id);
if (!ctx)
return;
if (ctx_id == 0)
res = vrend_resource_lookup(res_handle, ctx_id);
else
res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
if (!res) {
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
return;
}
if (!box)
return;
if (res->iov && (!iov || num_iovs == 0)) {
iov = res->iov;
num_iovs = res->num_iovs;
}
if (!iov) {
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
return;
}
if (!check_tsend_bounds(res, level, box))
return;
if (res->target == 0 && res->ptr) { if (res->target == 0 && res->ptr) {
uint32_t send_size = box->width * util_format_get_blocksize(res->base.format); uint32_t send_size = info->box->width * util_format_get_blocksize(res->base.format);
vrend_transfer_write_return(res->ptr + box->x, send_size, offset, iov, num_iovs); vrend_transfer_write_return(res->ptr + info->box->x, send_size, info->offset, iov, num_iovs);
return; return 0;
} }
vrend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); vrend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE);
@ -4147,15 +4106,15 @@ void vrend_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id,
res->target == GL_TRANSFORM_FEEDBACK_BUFFER || res->target == GL_TRANSFORM_FEEDBACK_BUFFER ||
res->target == GL_TEXTURE_BUFFER || res->target == GL_TEXTURE_BUFFER ||
res->target == GL_UNIFORM_BUFFER) { res->target == GL_UNIFORM_BUFFER) {
uint32_t send_size = box->width * util_format_get_blocksize(res->base.format); uint32_t send_size = info->box->width * util_format_get_blocksize(res->base.format);
void *data; void *data;
glBindBufferARB(res->target, res->id); glBindBufferARB(res->target, res->id);
data = glMapBufferRange(res->target, box->x, box->width, GL_MAP_READ_BIT); data = glMapBufferRange(res->target, info->box->x, info->box->width, GL_MAP_READ_BIT);
if (!data) if (!data)
fprintf(stderr,"unable to open buffer for reading %d\n", res->target); fprintf(stderr,"unable to open buffer for reading %d\n", res->target);
else else
vrend_transfer_write_return(data, send_size, offset, iov, num_iovs); vrend_transfer_write_return(data, send_size, info->offset, iov, num_iovs);
glUnmapBuffer(res->target); glUnmapBuffer(res->target);
} else { } else {
boolean can_readpixels = TRUE; boolean can_readpixels = TRUE;
@ -4163,15 +4122,66 @@ void vrend_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id,
can_readpixels = vrend_format_can_render(res->base.format) || vrend_format_is_ds(res->base.format); can_readpixels = vrend_format_can_render(res->base.format) || vrend_format_is_ds(res->base.format);
if (can_readpixels) { if (can_readpixels) {
vrend_transfer_send_readpixels(res, level, stride, box, offset, return vrend_transfer_send_readpixels(ctx, res,
iov, num_iovs); iov, num_iovs, info);
return;
} }
vrend_transfer_send_getteximage(res, level, stride, box, offset, return vrend_transfer_send_getteximage(ctx, res,
iov, num_iovs); iov, num_iovs, info);
}
return 0;
}
int vrend_renderer_transfer_iov(const struct vrend_transfer_info *info,
int transfer_mode)
{
struct vrend_resource *res;
struct vrend_context *ctx = vrend_lookup_renderer_ctx(info->ctx_id);
struct iovec *iov;
int num_iovs;
if (!info->box)
return EINVAL;
ctx = vrend_lookup_renderer_ctx(info->ctx_id);
if (!ctx)
return EINVAL;
if (info->ctx_id == 0)
res = vrend_resource_lookup(info->handle, 0);
else
res = vrend_renderer_ctx_res_lookup(ctx, info->handle);
if (!res) {
if (info->ctx_id)
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, info->handle);
return EINVAL;
} }
iov = info->iovec;
num_iovs = info->iovec_cnt;
if (res->iov && (!iov || num_iovs == 0)) {
iov = res->iov;
num_iovs = res->num_iovs;
}
if (!iov) {
if (info->ctx_id)
report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, info->handle);
return EINVAL;
}
if (!check_transfer_bounds(res, info->level, info->box))
return EINVAL;
if (transfer_mode == VREND_TRANSFER_WRITE)
return vrend_renderer_transfer_write_iov(ctx, res, iov, num_iovs,
info);
else
return vrend_renderer_transfer_send_iov(ctx, res, iov, num_iovs,
info);
} }
void vrend_set_stencil_ref(struct vrend_context *ctx, void vrend_set_stencil_ref(struct vrend_context *ctx,
@ -5364,9 +5374,11 @@ void vrend_renderer_get_rect(int res_handle, struct iovec *iov, unsigned int num
uint32_t offset, int x, int y, int width, int height) uint32_t offset, int x, int y, int width, int height)
{ {
struct vrend_resource *res = vrend_resource_lookup(res_handle, 0); struct vrend_resource *res = vrend_resource_lookup(res_handle, 0);
struct vrend_transfer_info transfer_info;
struct pipe_box box; struct pipe_box box;
int elsize; int elsize;
int stride;
memset(&transfer_info, 0, sizeof(transfer_info));
elsize = util_format_get_blocksize(res->base.format); elsize = util_format_get_blocksize(res->base.format);
box.x = x; box.x = x;
@ -5376,11 +5388,16 @@ void vrend_renderer_get_rect(int res_handle, struct iovec *iov, unsigned int num
box.height = height; box.height = height;
box.depth = 1; box.depth = 1;
stride = util_format_get_nblocksx(res->base.format, res->base.width0) * elsize; transfer_info.box = &box;
vrend_renderer_transfer_send_iov(res->handle, 0,
0, stride, 0, &box, offset, iov, num_iovs); transfer_info.stride = util_format_get_nblocksx(res->base.format, res->base.width0) * elsize;
transfer_info.offset = offset;
transfer_info.handle = res->handle;
transfer_info.iovec = iov;
transfer_info.iovec_cnt = num_iovs;
vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_READ);
} }
void vrend_renderer_attach_res_ctx(int ctx_id, int resource_id) void vrend_renderer_attach_res_ctx(int ctx_id, int resource_id)
{ {
struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id);

@ -222,15 +222,21 @@ void vrend_set_index_buffer(struct vrend_context *ctx,
uint32_t index_size, uint32_t index_size,
uint32_t offset); uint32_t offset);
void vrend_renderer_transfer_write_iov(uint32_t handle, struct vrend_transfer_info {
uint32_t ctx_id, uint32_t handle;
int level, uint32_t ctx_id;
uint32_t stride, int level;
uint32_t layer_stride, uint32_t stride;
struct pipe_box *box, uint32_t layer_stride;
uint64_t offset, struct pipe_box *box;
struct iovec *iovec, uint64_t offset;
unsigned int iovec_cnt); struct iovec *iovec;
unsigned int iovec_cnt;
};
#define VREND_TRANSFER_WRITE 1
#define VREND_TRANSFER_READ 2
int vrend_renderer_transfer_iov(const struct vrend_transfer_info *info, int transfer_mode);
void vrend_renderer_resource_copy_region(struct vrend_context *ctx, void vrend_renderer_resource_copy_region(struct vrend_context *ctx,
uint32_t dst_handle, uint32_t dst_level, uint32_t dst_handle, uint32_t dst_level,
@ -242,12 +248,6 @@ void vrend_renderer_blit(struct vrend_context *ctx,
uint32_t dst_handle, uint32_t src_handle, uint32_t dst_handle, uint32_t src_handle,
const struct pipe_blit_info *info); const struct pipe_blit_info *info);
void vrend_renderer_transfer_send_iov(uint32_t handle, uint32_t ctx_id,
uint32_t level, uint32_t stride,
uint32_t layer_stride,
struct pipe_box *box,
uint64_t offset, struct iovec *iov,
int iovec_cnt);
void vrend_set_stencil_ref(struct vrend_context *ctx, struct pipe_stencil_ref *ref); void vrend_set_stencil_ref(struct vrend_context *ctx, struct pipe_stencil_ref *ref);
void vrend_set_blend_color(struct vrend_context *ctx, struct pipe_blend_color *color); void vrend_set_blend_color(struct vrend_context *ctx, struct pipe_blend_color *color);
void vrend_set_scissor_state(struct vrend_context *ctx, struct pipe_scissor_state *ss); void vrend_set_scissor_state(struct vrend_context *ctx, struct pipe_scissor_state *ss);

Loading…
Cancel
Save