SVGA3dSurfaceFormat svga_translate_format_render(enum pipe_format format) { switch(format) { case PIPE_FORMAT_B8G8R8A8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_B5G5R5A1_UNORM: case PIPE_FORMAT_B4G4R4A4_UNORM: case PIPE_FORMAT_B5G6R5_UNORM: case PIPE_FORMAT_S8_USCALED_Z24_UNORM: case PIPE_FORMAT_X8Z24_UNORM: case PIPE_FORMAT_Z32_UNORM: case PIPE_FORMAT_Z16_UNORM: case PIPE_FORMAT_L8_UNORM: return svga_translate_format(format); #if 1 /* For on host conversion */ case PIPE_FORMAT_DXT1_RGB: return SVGA3D_X8R8G8B8; case PIPE_FORMAT_DXT1_RGBA: case PIPE_FORMAT_DXT3_RGBA: case PIPE_FORMAT_DXT5_RGBA: return SVGA3D_A8R8G8B8; #endif default: return SVGA3D_FORMAT_INVALID; } }
SVGA3dSurfaceFormat svga_translate_format_render(enum pipe_format format) { switch(format) { case PIPE_FORMAT_B8G8R8A8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_B5G5R5A1_UNORM: case PIPE_FORMAT_B4G4R4A4_UNORM: case PIPE_FORMAT_B5G6R5_UNORM: case PIPE_FORMAT_S8_USCALED_Z24_UNORM: case PIPE_FORMAT_X8Z24_UNORM: case PIPE_FORMAT_Z32_UNORM: case PIPE_FORMAT_Z16_UNORM: case PIPE_FORMAT_L8_UNORM: return svga_translate_format(format); default: return SVGA3D_FORMAT_INVALID; } }
/** * Implement pipe_screen::is_format_supported(). * \param bindings bitmask of PIPE_BIND_x flags */ static boolean svga_is_format_supported( struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bindings) { struct svga_screen *ss = svga_screen(screen); SVGA3dSurfaceFormat svga_format; SVGA3dSurfaceFormatCaps caps; SVGA3dSurfaceFormatCaps mask; assert(bindings); if (sample_count > 1) { /* In ms_samples, if bit N is set it means that we support * multisample with N+1 samples per pixel. */ if ((ss->ms_samples & (1 << (sample_count - 1))) == 0) { return FALSE; } } svga_format = svga_translate_format(ss, format, bindings); if (svga_format == SVGA3D_FORMAT_INVALID) { return FALSE; } /* we don't support sRGB rendering into display targets */ if (util_format_is_srgb(format) && (bindings & PIPE_BIND_DISPLAY_TARGET)) { return FALSE; } /* * For VGPU10 vertex formats, skip querying host capabilities */ if (ss->sws->have_vgpu10 && (bindings & PIPE_BIND_VERTEX_BUFFER)) { SVGA3dSurfaceFormat svga_format; unsigned flags; svga_translate_vertex_format_vgpu10(format, &svga_format, &flags); return svga_format != SVGA3D_FORMAT_INVALID; } /* * Override host capabilities, so that we end up with the same * visuals for all virtual hardware implementations. */ if (bindings & PIPE_BIND_DISPLAY_TARGET) { switch (svga_format) { case SVGA3D_A8R8G8B8: case SVGA3D_X8R8G8B8: case SVGA3D_R5G6B5: break; /* VGPU10 formats */ case SVGA3D_B8G8R8A8_UNORM: case SVGA3D_B8G8R8X8_UNORM: case SVGA3D_B5G6R5_UNORM: break; /* Often unsupported/problematic. This means we end up with the same * visuals for all virtual hardware implementations. */ case SVGA3D_A4R4G4B4: case SVGA3D_A1R5G5B5: return FALSE; default: return FALSE; } } /* * Query the host capabilities. */ svga_get_format_cap(ss, svga_format, &caps); if (bindings & PIPE_BIND_RENDER_TARGET) { /* Check that the color surface is blendable, unless it's an * integer format. */ if (!svga_format_is_integer(svga_format) && (caps.value & SVGA3DFORMAT_OP_NOALPHABLEND)) { return FALSE; } } mask.value = 0; if (bindings & PIPE_BIND_RENDER_TARGET) { mask.value |= SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET; } if (bindings & PIPE_BIND_DEPTH_STENCIL) { mask.value |= SVGA3DFORMAT_OP_ZSTENCIL; } if (bindings & PIPE_BIND_SAMPLER_VIEW) { mask.value |= SVGA3DFORMAT_OP_TEXTURE; } if (target == PIPE_TEXTURE_CUBE) { mask.value |= SVGA3DFORMAT_OP_CUBETEXTURE; } else if (target == PIPE_TEXTURE_3D) { mask.value |= SVGA3DFORMAT_OP_VOLUMETEXTURE; } return (caps.value & mask.value) == mask.value; }
/** * Implemnt pipe_screen::is_format_supported(). * \param bindings bitmask of PIPE_BIND_x flags */ static boolean svga_is_format_supported( struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bindings) { struct svga_screen *ss = svga_screen(screen); SVGA3dSurfaceFormat svga_format; SVGA3dSurfaceFormatCaps caps; SVGA3dSurfaceFormatCaps mask; assert(bindings); if (sample_count > 1) { return FALSE; } svga_format = svga_translate_format(ss, format, bindings); if (svga_format == SVGA3D_FORMAT_INVALID) { return FALSE; } /* * Override host capabilities, so that we end up with the same * visuals for all virtual hardware implementations. */ if (bindings & PIPE_BIND_DISPLAY_TARGET) { switch (svga_format) { case SVGA3D_A8R8G8B8: case SVGA3D_X8R8G8B8: case SVGA3D_R5G6B5: break; /* Often unsupported/problematic. This means we end up with the same * visuals for all virtual hardware implementations. */ case SVGA3D_A4R4G4B4: case SVGA3D_A1R5G5B5: return FALSE; default: return FALSE; } } /* * Query the host capabilities. */ svga_get_format_cap(ss, svga_format, &caps); mask.value = 0; if (bindings & PIPE_BIND_RENDER_TARGET) { mask.offscreenRenderTarget = 1; } if (bindings & PIPE_BIND_DEPTH_STENCIL) { mask.zStencil = 1; } if (bindings & PIPE_BIND_SAMPLER_VIEW) { mask.texture = 1; } if (target == PIPE_TEXTURE_CUBE) { mask.cubeTexture = 1; } if (target == PIPE_TEXTURE_3D) { mask.volumeTexture = 1; } return (caps.value & mask.value) == mask.value; }
static struct pipe_surface * svga_get_tex_surface(struct pipe_screen *screen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned flags) { struct svga_texture *tex = svga_texture(pt); struct svga_surface *s; boolean render = (flags & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) ? TRUE : FALSE; boolean view = FALSE; SVGA3dSurfaceFormat format; s = CALLOC_STRUCT(svga_surface); if (!s) return NULL; pipe_reference_init(&s->base.reference, 1); pipe_resource_reference(&s->base.texture, pt); s->base.format = pt->format; s->base.width = u_minify(pt->width0, level); s->base.height = u_minify(pt->height0, level); s->base.usage = flags; s->base.level = level; s->base.face = face; s->base.zslice = zslice; if (!render) format = svga_translate_format(pt->format); else format = svga_translate_format_render(pt->format); assert(format != SVGA3D_FORMAT_INVALID); if (svga_screen(screen)->debug.force_surface_view) view = TRUE; /* Currently only used for compressed textures */ if (render && format != svga_translate_format(pt->format)) { view = TRUE; } if (level != 0 && svga_screen(screen)->debug.force_level_surface_view) view = TRUE; if (pt->target == PIPE_TEXTURE_3D) view = TRUE; if (svga_screen(screen)->debug.no_surface_view) view = FALSE; if (view) { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u face %u z %u, %p\n", pt, level, face, zslice, s); s->handle = svga_texture_view_surface(NULL, tex, format, level, 1, face, zslice, &s->key); s->real_face = 0; s->real_level = 0; s->real_zslice = 0; } else { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, face %u, z %u, %p\n", pt, level, face, zslice, s); memset(&s->key, 0, sizeof s->key); s->handle = tex->handle; s->real_face = face; s->real_level = level; s->real_zslice = zslice; } return &s->base; }
struct svga_sampler_view * svga_get_tex_sampler_view(struct pipe_context *pipe, struct pipe_resource *pt, unsigned min_lod, unsigned max_lod) { struct svga_context *svga = svga_context(pipe); struct svga_screen *ss = svga_screen(pipe->screen); struct svga_texture *tex = svga_texture(pt); struct svga_sampler_view *sv = NULL; SVGA3dSurfaceFlags flags = SVGA3D_SURFACE_HINT_TEXTURE; SVGA3dSurfaceFormat format = svga_translate_format(ss, pt->format, PIPE_BIND_SAMPLER_VIEW); boolean view = TRUE; assert(pt); assert(min_lod <= max_lod); assert(max_lod <= pt->last_level); assert(!svga_have_vgpu10(svga)); /* Is a view needed */ { /* * Can't control max lod. For first level views and when we only * look at one level we disable mip filtering to achive the same * results as a view. */ if (min_lod == 0 && max_lod >= pt->last_level) view = FALSE; if (ss->debug.no_sampler_view) view = FALSE; if (ss->debug.force_sampler_view) view = TRUE; } /* First try the cache */ if (view) { mtx_lock(&ss->tex_mutex); if (tex->cached_view && tex->cached_view->min_lod == min_lod && tex->cached_view->max_lod == max_lod) { svga_sampler_view_reference(&sv, tex->cached_view); mtx_unlock(&ss->tex_mutex); SVGA_DBG(DEBUG_VIEWS, "svga: Sampler view: reuse %p, %u %u, last %u\n", pt, min_lod, max_lod, pt->last_level); svga_validate_sampler_view(svga_context(pipe), sv); return sv; } mtx_unlock(&ss->tex_mutex); } sv = CALLOC_STRUCT(svga_sampler_view); if (!sv) return NULL; pipe_reference_init(&sv->reference, 1); /* Note: we're not refcounting the texture resource here to avoid * a circular dependency. */ sv->texture = pt; sv->min_lod = min_lod; sv->max_lod = max_lod; /* No view needed just use the whole texture */ if (!view) { SVGA_DBG(DEBUG_VIEWS, "svga: Sampler view: no %p, mips %u..%u, nr %u, size (%ux%ux%u), last %u\n", pt, min_lod, max_lod, max_lod - min_lod + 1, pt->width0, pt->height0, pt->depth0, pt->last_level); sv->key.cachable = 0; sv->handle = tex->handle; debug_reference(&sv->reference, (debug_reference_descriptor)svga_debug_describe_sampler_view, 0); return sv; } SVGA_DBG(DEBUG_VIEWS, "svga: Sampler view: yes %p, mips %u..%u, nr %u, size (%ux%ux%u), last %u\n", pt, min_lod, max_lod, max_lod - min_lod + 1, pt->width0, pt->height0, pt->depth0, pt->last_level); sv->age = tex->age; sv->handle = svga_texture_view_surface(svga, tex, PIPE_BIND_SAMPLER_VIEW, flags, format, min_lod, max_lod - min_lod + 1, -1, 1, -1, FALSE, &sv->key); if (!sv->handle) { sv->key.cachable = 0; sv->handle = tex->handle; debug_reference(&sv->reference, (debug_reference_descriptor) svga_debug_describe_sampler_view, 0); return sv; } mtx_lock(&ss->tex_mutex); svga_sampler_view_reference(&tex->cached_view, sv); mtx_unlock(&ss->tex_mutex); debug_reference(&sv->reference, (debug_reference_descriptor) svga_debug_describe_sampler_view, 0); return sv; }
/** * Create a DX ShaderResourceSamplerView for the given pipe_sampler_view, * if needed. */ enum pipe_error svga_validate_pipe_sampler_view(struct svga_context *svga, struct svga_pipe_sampler_view *sv) { enum pipe_error ret = PIPE_OK; if (sv->id == SVGA3D_INVALID_ID) { struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_resource *texture = sv->base.texture; struct svga_winsys_surface *surface = svga_resource_handle(texture); SVGA3dSurfaceFormat format; SVGA3dResourceType resourceDim; SVGA3dShaderResourceViewDesc viewDesc; enum pipe_format viewFormat = sv->base.format; /* vgpu10 cannot create a BGRX view for a BGRA resource, so force it to * create a BGRA view (and vice versa). */ if (viewFormat == PIPE_FORMAT_B8G8R8X8_UNORM && svga_texture_device_format_has_alpha(texture)) { viewFormat = PIPE_FORMAT_B8G8R8A8_UNORM; } else if (viewFormat == PIPE_FORMAT_B8G8R8A8_UNORM && !svga_texture_device_format_has_alpha(texture)) { viewFormat = PIPE_FORMAT_B8G8R8X8_UNORM; } format = svga_translate_format(ss, viewFormat, PIPE_BIND_SAMPLER_VIEW); assert(format != SVGA3D_FORMAT_INVALID); /* Convert the format to a sampler-friendly format, if needed */ format = svga_sampler_format(format); if (texture->target == PIPE_BUFFER) { unsigned elem_size = util_format_get_blocksize(sv->base.format); viewDesc.buffer.firstElement = sv->base.u.buf.offset / elem_size; viewDesc.buffer.numElements = sv->base.u.buf.size / elem_size; } else { viewDesc.tex.mostDetailedMip = sv->base.u.tex.first_level; viewDesc.tex.firstArraySlice = sv->base.u.tex.first_layer; viewDesc.tex.mipLevels = (sv->base.u.tex.last_level - sv->base.u.tex.first_level + 1); } /* arraySize in viewDesc specifies the number of array slices in a * texture array. For 3D texture, last_layer in * pipe_sampler_view specifies the last slice of the texture * which is different from the last slice in a texture array, * hence we need to set arraySize to 1 explicitly. */ viewDesc.tex.arraySize = (texture->target == PIPE_TEXTURE_3D || texture->target == PIPE_BUFFER) ? 1 : (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1); switch (texture->target) { case PIPE_BUFFER: resourceDim = SVGA3D_RESOURCE_BUFFER; break; case PIPE_TEXTURE_1D: case PIPE_TEXTURE_1D_ARRAY: resourceDim = SVGA3D_RESOURCE_TEXTURE1D; break; case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_2D: case PIPE_TEXTURE_2D_ARRAY: resourceDim = SVGA3D_RESOURCE_TEXTURE2D; break; case PIPE_TEXTURE_3D: resourceDim = SVGA3D_RESOURCE_TEXTURE3D; break; case PIPE_TEXTURE_CUBE: case PIPE_TEXTURE_CUBE_ARRAY: resourceDim = SVGA3D_RESOURCE_TEXTURECUBE; break; default: assert(!"Unexpected texture type"); resourceDim = SVGA3D_RESOURCE_TEXTURE2D; } sv->id = util_bitmask_add(svga->sampler_view_id_bm); ret = SVGA3D_vgpu10_DefineShaderResourceView(svga->swc, sv->id, surface, format, resourceDim, &viewDesc); if (ret != PIPE_OK) { util_bitmask_clear(svga->sampler_view_id_bm, sv->id); sv->id = SVGA3D_INVALID_ID; } } return ret; }
/** * A helper function to create a surface view. * The view boolean flag specifies whether svga_texture_view_surface() * will be called to create a cloned surface and resource for the view. */ static struct pipe_surface * svga_create_surface_view(struct pipe_context *pipe, struct pipe_resource *pt, const struct pipe_surface *surf_tmpl, boolean view) { struct svga_context *svga = svga_context(pipe); struct svga_texture *tex = svga_texture(pt); struct pipe_screen *screen = pipe->screen; struct svga_screen *ss = svga_screen(screen); struct svga_surface *s; unsigned layer, zslice, bind; unsigned nlayers = 1; SVGA3dSurfaceFlags flags = 0; SVGA3dSurfaceFormat format; s = CALLOC_STRUCT(svga_surface); if (!s) return NULL; if (pt->target == PIPE_TEXTURE_CUBE) { layer = surf_tmpl->u.tex.first_layer; zslice = 0; } else if (pt->target == PIPE_TEXTURE_1D_ARRAY || pt->target == PIPE_TEXTURE_2D_ARRAY) { layer = surf_tmpl->u.tex.first_layer; zslice = 0; nlayers = surf_tmpl->u.tex.last_layer - surf_tmpl->u.tex.first_layer + 1; } else { layer = 0; zslice = surf_tmpl->u.tex.first_layer; } pipe_reference_init(&s->base.reference, 1); pipe_resource_reference(&s->base.texture, pt); s->base.context = pipe; s->base.format = surf_tmpl->format; s->base.width = u_minify(pt->width0, surf_tmpl->u.tex.level); s->base.height = u_minify(pt->height0, surf_tmpl->u.tex.level); s->base.u.tex.level = surf_tmpl->u.tex.level; s->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer; s->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; s->view_id = SVGA3D_INVALID_ID; s->backed = NULL; if (util_format_is_depth_or_stencil(surf_tmpl->format)) { flags = SVGA3D_SURFACE_HINT_DEPTHSTENCIL | SVGA3D_SURFACE_BIND_DEPTH_STENCIL; bind = PIPE_BIND_DEPTH_STENCIL; } else { flags = SVGA3D_SURFACE_HINT_RENDERTARGET | SVGA3D_SURFACE_BIND_RENDER_TARGET; bind = PIPE_BIND_RENDER_TARGET; } if (tex->imported) format = tex->key.format; else format = svga_translate_format(ss, surf_tmpl->format, bind); assert(format != SVGA3D_FORMAT_INVALID); if (view) { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u layer %u z %u, %p\n", pt, surf_tmpl->u.tex.level, layer, zslice, s); if (svga_have_vgpu10(svga)) { switch (pt->target) { case PIPE_TEXTURE_1D: flags |= SVGA3D_SURFACE_1D; break; case PIPE_TEXTURE_1D_ARRAY: flags |= SVGA3D_SURFACE_1D | SVGA3D_SURFACE_ARRAY; break; case PIPE_TEXTURE_2D_ARRAY: flags |= SVGA3D_SURFACE_ARRAY; break; case PIPE_TEXTURE_3D: flags |= SVGA3D_SURFACE_VOLUME; break; case PIPE_TEXTURE_CUBE: if (nlayers == 6) flags |= SVGA3D_SURFACE_CUBEMAP; break; default: break; } } /* When we clone the surface view resource, use the format used in * the creation of the original resource. */ s->handle = svga_texture_view_surface(svga, tex, bind, flags, tex->key.format, surf_tmpl->u.tex.level, 1, layer, nlayers, zslice, &s->key); if (!s->handle) { FREE(s); return NULL; } s->key.format = format; s->real_layer = 0; s->real_level = 0; s->real_zslice = 0; } else { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, layer %u, z %u, %p\n", pt, surf_tmpl->u.tex.level, layer, zslice, s); memset(&s->key, 0, sizeof s->key); s->key.format = format; s->handle = tex->handle; s->real_layer = layer; s->real_zslice = zslice; s->real_level = surf_tmpl->u.tex.level; } svga->hud.num_surface_views++; return &s->base; }
static struct pipe_surface * svga_create_surface(struct pipe_context *pipe, struct pipe_resource *pt, const struct pipe_surface *surf_tmpl) { struct svga_context *svga = svga_context(pipe); struct svga_texture *tex = svga_texture(pt); struct pipe_screen *screen = pipe->screen; struct svga_screen *ss = svga_screen(screen); struct svga_surface *s; unsigned face, zslice; boolean view = FALSE; SVGA3dSurfaceFlags flags; SVGA3dSurfaceFormat format; assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); s = CALLOC_STRUCT(svga_surface); if (!s) return NULL; if (pt->target == PIPE_TEXTURE_CUBE) { face = surf_tmpl->u.tex.first_layer; zslice = 0; } else { face = 0; zslice = surf_tmpl->u.tex.first_layer; } pipe_reference_init(&s->base.reference, 1); pipe_resource_reference(&s->base.texture, pt); s->base.context = pipe; s->base.format = surf_tmpl->format; s->base.width = u_minify(pt->width0, surf_tmpl->u.tex.level); s->base.height = u_minify(pt->height0, surf_tmpl->u.tex.level); s->base.u.tex.level = surf_tmpl->u.tex.level; s->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer; s->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; if (util_format_is_depth_or_stencil(surf_tmpl->format)) { flags = SVGA3D_SURFACE_HINT_DEPTHSTENCIL; } else { flags = SVGA3D_SURFACE_HINT_RENDERTARGET; } format = svga_translate_format(ss, surf_tmpl->format, 0); assert(format != SVGA3D_FORMAT_INVALID); if (svga_screen(screen)->debug.force_surface_view) view = TRUE; /* Currently only used for compressed textures */ if (format != svga_translate_format(ss, surf_tmpl->format, 0)) { view = TRUE; } if (surf_tmpl->u.tex.level != 0 && svga_screen(screen)->debug.force_level_surface_view) view = TRUE; if (pt->target == PIPE_TEXTURE_3D) view = TRUE; if (svga_screen(screen)->debug.no_surface_view) view = FALSE; if (view) { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u face %u z %u, %p\n", pt, surf_tmpl->u.tex.level, face, zslice, s); s->handle = svga_texture_view_surface(svga, tex, flags, format, surf_tmpl->u.tex.level, 1, face, zslice, &s->key); s->real_face = 0; s->real_level = 0; s->real_zslice = 0; } else { SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, face %u, z %u, %p\n", pt, surf_tmpl->u.tex.level, face, zslice, s); memset(&s->key, 0, sizeof s->key); s->handle = tex->handle; s->real_face = face; s->real_zslice = zslice; s->real_level = surf_tmpl->u.tex.level; } return &s->base; }