#include "pan_screen.h"
#include "pan_resource.h"
#include "pan_swizzle.h"
+#include "pan_util.h"
static struct pipe_resource *
panfrost_resource_from_handle(struct pipe_screen *pscreen,
rsc->bo = screen->driver->import_bo(screen, whandle);
+ if (screen->ro) {
+ rsc->scanout =
+ renderonly_create_gpu_import_for_resource(prsc, screen->ro, NULL);
+ /* failure is expected in some cases.. */
+ }
+
return prsc;
}
handle->stride = stride;
handle->modifier = DRM_FORMAT_MOD_INVALID;
- if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
- printf("Missed shared handle\n");
- return FALSE;
- } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
- if (renderonly_get_handle(scanout, handle)) {
- return TRUE;
- } else {
- printf("Missed nonrenderonly KMS handle for resource %p with scanout %p\n", pt, scanout);
- return FALSE;
- }
- } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
+ if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
+ return FALSE;
+ } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
+ if (renderonly_get_handle(scanout, handle))
+ return TRUE;
+
+ handle->handle = rsrc->bo->gem_handle;
+ return TRUE;
+ } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
if (scanout) {
struct drm_prime_handle args = {
.handle = scanout->handle,
handle->handle = args.fd;
return TRUE;
- } else {
- printf("Missed nonscanout FD handle\n");
- assert(0);
- return FALSE;
- }
- }
+ } else
+ return screen->driver->export_bo(screen, rsrc->bo->gem_handle, handle);
+ }
- return FALSE;
+ return FALSE;
}
static void
panfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
{
- //fprintf(stderr, "TODO %s\n", __func__);
+ //DBG("TODO %s\n", __func__);
}
static void
const struct pipe_blit_info *info)
{
/* STUB */
- printf("Skipping blit XXX\n");
+ DBG("Skipping blit XXX\n");
return;
}
panfrost_create_bo(struct panfrost_screen *screen, const struct pipe_resource *template)
{
struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo);
+
+ /* Calculate the size of the bo */
+
int bytes_per_pixel = util_format_get_blocksize(template->format);
int stride = bytes_per_pixel * template->width0; /* TODO: Alignment? */
size_t sz = stride;
if (template->height0) sz *= template->height0;
-
if (template->depth0) sz *= template->depth0;
- if ((template->bind & PIPE_BIND_RENDER_TARGET) || (template->bind & PIPE_BIND_DEPTH_STENCIL)) {
- /* TODO: Mipmapped RTs */
- //assert(template->last_level == 0);
-
- /* Allocate the framebuffer as its own slab of GPU-accessible memory */
- struct panfrost_memory slab;
- screen->driver->allocate_slab(screen, &slab, (sz / 4096) + 1, false, 0, 0, 0);
-
- /* Make the resource out of the slab */
- bo->cpu[0] = slab.cpu;
- bo->gpu[0] = slab.gpu;
- } else {
- /* TODO: For linear resources, allocate straight on the cmdstream for
- * zero-copy operation */
-
- /* Tiling textures is almost always faster, unless we only use it once */
- bo->tiled = (template->usage != PIPE_USAGE_STREAM) && (template->bind & PIPE_BIND_SAMPLER_VIEW);
+ /* Depth buffers require extra space for unknown reasons */
+
+ if (template->bind & PIPE_BIND_DEPTH_STENCIL)
+ sz = sz + sz/256;
+
+ /* Based on the usage, figure out what storing will be used. There are
+ * various tradeoffs:
+ *
+ * Linear: the basic format, bad for memory bandwidth, bad for cache
+ * use. Zero-copy, though. Renderable.
+ *
+ * Tiled: Not compressed, but cache-optimized. Expensive to write into
+ * (due to software tiling), but cheap to sample from. Ideal for most
+ * textures.
+ *
+ * AFBC: Compressed and renderable (so always desirable for non-scanout
+ * rendertargets). Cheap to sample from. The format is black box, so we
+ * can't read/write from software.
+ */
+
+ /* Tiling textures is almost always faster, unless we only use it once */
+ bool should_tile = (template->usage != PIPE_USAGE_STREAM) && (template->bind & PIPE_BIND_SAMPLER_VIEW);
+
+ /* Set the layout appropriately */
+ bo->layout = should_tile ? PAN_TILED : PAN_LINEAR;
+
+ if (bo->layout == PAN_TILED) {
+ /* For tiled, we don't map directly, so just malloc any old buffer */
+
+ for (int l = 0; l < (template->last_level + 1); ++l) {
+ bo->cpu[l] = malloc(sz);
+ bo->size[l] = sz;
+ sz >>= 2;
+ }
+ } else {
+ /* For a linear resource, allocate a block of memory from
+ * kernel space */
- if (bo->tiled) {
- /* For tiled, we don't map directly, so just malloc any old buffer */
+ struct panfrost_memory mem;
- for (int l = 0; l < (template->last_level + 1); ++l) {
- bo->cpu[l] = malloc(sz);
- //sz >>= 2;
- }
- } else {
- /* But for linear, we can! */
+ bo->size[0] = ALIGN(sz, 4096);
+ screen->driver->allocate_slab(screen, &mem, bo->size[0] / 4096, true, 0, 0, 0);
- struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, sz, HEAP_TEXTURE);
- struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
- struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
- bo->entry[0] = p_entry;
- bo->cpu[0] = backing->cpu + p_entry->offset;
- bo->gpu[0] = backing->gpu + p_entry->offset;
+ bo->cpu[0] = mem.cpu;
+ bo->gpu[0] = mem.gpu;
+ bo->gem_handle = mem.gem_handle;
- /* TODO: Mipmap */
- }
- }
+ /* TODO: Mipmap */
+ }
return bo;
}
case PIPE_TEXTURE_RECT:
break;
default:
- fprintf(stderr, "Unknown texture target %d\n", template->target);
+ DBG("Unknown texture target %d\n", template->target);
assert(0);
}
- if ((template->bind & PIPE_BIND_RENDER_TARGET) || (template->bind & PIPE_BIND_DEPTH_STENCIL)) {
- if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
- template->bind & PIPE_BIND_SCANOUT ||
- template->bind & PIPE_BIND_SHARED) {
- struct pipe_resource scanout_templat = *template;
- struct renderonly_scanout *scanout;
- struct winsys_handle handle;
-
- /* TODO: align width0 and height0? */
-
- scanout = renderonly_scanout_for_resource(&scanout_templat,
- pscreen->ro, &handle);
- if (!scanout)
- return NULL;
-
- assert(handle.type == WINSYS_HANDLE_TYPE_FD);
- /* TODO: handle modifiers? */
- so = pan_resource(screen->resource_from_handle(screen, template,
- &handle,
- PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
- close(handle.handle);
- if (!so)
- return NULL;
-
- so->scanout = scanout;
- pscreen->display_target = so;
- } else {
- so->bo = panfrost_create_bo(pscreen, template);
- }
+ if (template->bind & PIPE_BIND_DISPLAY_TARGET ||
+ template->bind & PIPE_BIND_SCANOUT ||
+ template->bind & PIPE_BIND_SHARED) {
+ struct pipe_resource scanout_templat = *template;
+ struct renderonly_scanout *scanout;
+ struct winsys_handle handle;
+
+ /* TODO: align width0 and height0? */
+
+ scanout = renderonly_scanout_for_resource(&scanout_templat,
+ pscreen->ro, &handle);
+ if (!scanout)
+ return NULL;
+
+ assert(handle.type == WINSYS_HANDLE_TYPE_FD);
+ /* TODO: handle modifiers? */
+ so = pan_resource(screen->resource_from_handle(screen, template,
+ &handle,
+ PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
+ close(handle.handle);
+ if (!so)
+ return NULL;
+
+ so->scanout = scanout;
+ pscreen->display_target = so;
} else {
- so->bo = panfrost_create_bo(pscreen, template);
+ so->bo = panfrost_create_bo(pscreen, template);
}
- printf("Created resource %p with scanout %p\n", so, so->scanout);
-
return (struct pipe_resource *)so;
}
{
struct panfrost_bo *bo = (struct panfrost_bo *)pbo;
- if (bo->tiled) {
- /* CPU is all malloc'ed, so just plain ol' free needed */
+ if (bo->layout == PAN_LINEAR && !bo->imported) {
+ /* Construct a memory object for all mip levels */
+
+ struct panfrost_memory mem = {
+ .cpu = bo->cpu[0],
+ .gpu = bo->gpu[0],
+ .size = bo->size[0],
+ .gem_handle = bo->gem_handle,
+ };
+
+ screen->driver->free_slab(screen, &mem);
+ }
+
+ if (bo->layout == PAN_TILED) {
+ /* Tiled has a malloc'd CPU, so just plain ol' free needed */
- for (int l = 0; bo->cpu[l]; l++) {
+ for (int l = 0; l < MAX_MIP_LEVELS; ++l) {
free(bo->cpu[l]);
}
- } else if (bo->entry[0] != NULL) {
- bo->entry[0]->freed = true;
- pb_slab_free(&screen->slabs, &bo->entry[0]->base);
- } else {
- /* TODO */
- printf("--leaking main allocation--\n");
}
- if (bo->has_afbc) {
+ if (bo->layout == PAN_AFBC) {
/* TODO */
- printf("--leaking afbc--\n");
+ DBG("--leaking afbc (%d bytes)--\n", bo->afbc_metadata_size);
}
if (bo->has_checksum) {
/* TODO */
- printf("--leaking checksum--\n");
+ DBG("--leaking checksum (%zd bytes)--\n", bo->checksum_slab.size);
+ }
+
+ if (bo->imported) {
+ screen->driver->free_imported_bo(screen, bo);
}
}
panfrost_resource_destroy(struct pipe_screen *screen,
struct pipe_resource *pt)
{
- struct panfrost_screen *pscreen = panfrost_screen(screen);
+ struct panfrost_screen *pscreen = pan_screen(screen);
struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
if (rsrc->scanout)
/* If non-zero level, it's a mipmapped resource and needs to be treated as such */
bo->is_mipmap |= transfer->level;
- if (transfer->usage & PIPE_TRANSFER_MAP_DIRECTLY && bo->tiled) {
- /* We cannot directly map tiled textures */
+ if (transfer->usage & PIPE_TRANSFER_MAP_DIRECTLY && bo->layout != PAN_LINEAR) {
+ /* We can only directly map linear resources */
return NULL;
}
int swizzled_sz = panfrost_swizzled_size(width, height, bytes_per_pixel);
- /* Allocate the transfer given that known size but do not copy */
- struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, swizzled_sz, HEAP_TEXTURE);
- struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
- struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
- uint8_t *swizzled = backing->cpu + p_entry->offset;
-
/* Save the entry. But if there was already an entry here (from a
* previous upload of the resource), free that one so we don't leak */
pb_slab_free(&screen->slabs, &bo->entry[level]->base);
}
+ /* Allocate the transfer given that known size but do not copy */
+ struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, swizzled_sz, HEAP_TEXTURE);
+ struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
+ struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
+ uint8_t *swizzled = backing->cpu + p_entry->offset;
+
bo->entry[level] = p_entry;
bo->gpu[level] = backing->gpu + p_entry->offset;
struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource;
/* Gallium thinks writeback happens here; instead, this is our cue to tile */
- if (bo->has_afbc) {
- printf("Warning: writes to afbc surface can't possibly work out well for you...\n");
- } else if (bo->tiled) {
+ if (bo->layout == PAN_AFBC) {
+ DBG("Warning: writes to afbc surface can't possibly work out well for you...\n");
+ } else if (bo->layout == PAN_TILED) {
struct pipe_context *gallium = (struct pipe_context *) ctx;
struct panfrost_screen *screen = pan_screen(gallium->screen);
panfrost_tile_texture(screen, prsrc, transfer->level);
static void
panfrost_slab_free(void *priv, struct pb_slab *slab)
{
- /* STUB */
- //struct panfrost_memory *mem = (struct panfrost_memory *) slab;
- printf("stub: Tried to free slab\n");
+ struct panfrost_memory *mem = (struct panfrost_memory *) slab;
+ struct panfrost_screen *screen = (struct panfrost_screen *) priv;
+
+ screen->driver->free_slab(screen, mem);
}
static void
panfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
{
- //fprintf(stderr, "TODO %s\n", __func__);
+ //DBG("TODO %s\n", __func__);
+}
+
+static enum pipe_format
+panfrost_resource_get_internal_format(struct pipe_resource *prsrc)
+{
+ return prsrc->format;
+}
+
+static void
+panfrost_resource_set_stencil(struct pipe_resource *prsrc,
+ struct pipe_resource *stencil)
+{
+ pan_resource(prsrc)->separate_stencil = pan_resource(stencil);
+}
+
+static struct pipe_resource *
+panfrost_resource_get_stencil(struct pipe_resource *prsrc)
+{
+ return &pan_resource(prsrc)->separate_stencil->base;
}
static const struct u_transfer_vtbl transfer_vtbl = {
.transfer_map = panfrost_transfer_map,
.transfer_unmap = panfrost_transfer_unmap,
.transfer_flush_region = u_default_transfer_flush_region,
- //.get_internal_format = panfrost_resource_get_internal_format,
- //.set_stencil = panfrost_resource_set_stencil,
- //.get_stencil = panfrost_resource_get_stencil,
+ .get_internal_format = panfrost_resource_get_internal_format,
+ .set_stencil = panfrost_resource_set_stencil,
+ .get_stencil = panfrost_resource_get_stencil,
};
void
pscreen->base.resource_from_handle = panfrost_resource_from_handle;
pscreen->base.resource_get_handle = panfrost_resource_get_handle;
pscreen->base.transfer_helper = u_transfer_helper_create(&transfer_vtbl,
- true, true,
+ true, false,
true, true);
pb_slabs_init(&pscreen->slabs,