mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 16:08:04 +02:00
panfrost: Check in sources for command stream
This patch includes the command stream portion of the driver, complementing the earlier compiler. It provides a base for future work, though it does not integrate with any particular winsys. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
parent
8f4485ef1a
commit
7da251fc72
22 changed files with 5441 additions and 5 deletions
|
|
@ -23,10 +23,23 @@ files_panfrost = files(
|
||||||
'pan_public.h',
|
'pan_public.h',
|
||||||
'pan_screen.c',
|
'pan_screen.c',
|
||||||
'pan_screen.h',
|
'pan_screen.h',
|
||||||
|
'pan_resource.c',
|
||||||
|
'pan_resource.h',
|
||||||
|
|
||||||
'midgard/midgard_compile.c',
|
'midgard/midgard_compile.c',
|
||||||
'midgard/cppwrap.cpp',
|
'midgard/cppwrap.cpp',
|
||||||
'midgard/disassemble.c',
|
'midgard/disassemble.c',
|
||||||
|
|
||||||
|
'pan_context.c',
|
||||||
|
'pan_drm.c',
|
||||||
|
'pan_allocate.c',
|
||||||
|
'pan_assemble.c',
|
||||||
|
'pan_format.c',
|
||||||
|
'pan_swizzle.c',
|
||||||
|
'pan_blending.c',
|
||||||
|
'pan_blend_shaders.c',
|
||||||
|
'pan_wallpaper.c',
|
||||||
|
'pan_pretty_print.c'
|
||||||
)
|
)
|
||||||
|
|
||||||
inc_panfrost = [
|
inc_panfrost = [
|
||||||
|
|
|
||||||
220
src/gallium/drivers/panfrost/pan_allocate.c
Normal file
220
src/gallium/drivers/panfrost/pan_allocate.c
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <panfrost-misc.h>
|
||||||
|
#include <panfrost-job.h>
|
||||||
|
#include "pan_context.h"
|
||||||
|
|
||||||
|
/* TODO: What does this actually have to be? */
|
||||||
|
#define ALIGNMENT 128
|
||||||
|
|
||||||
|
/* Allocate a mapped chunk directly from a heap */
|
||||||
|
|
||||||
|
struct panfrost_transfer
|
||||||
|
panfrost_allocate_chunk(struct panfrost_context *ctx, size_t size, unsigned heap_id)
|
||||||
|
{
|
||||||
|
size = ALIGN(size, ALIGNMENT);
|
||||||
|
|
||||||
|
struct pipe_context *gallium = (struct pipe_context *) ctx;
|
||||||
|
struct panfrost_screen *screen = panfrost_screen(gallium->screen);
|
||||||
|
|
||||||
|
struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, size, heap_id);
|
||||||
|
struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
|
||||||
|
struct panfrost_memory *backing = (struct panfrost_memory *) entry->slab;
|
||||||
|
|
||||||
|
struct panfrost_transfer transfer = {
|
||||||
|
.cpu = backing->cpu + p_entry->offset,
|
||||||
|
.gpu = backing->gpu + p_entry->offset
|
||||||
|
};
|
||||||
|
|
||||||
|
return transfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transient command stream pooling: command stream uploads try to simply copy
|
||||||
|
* into whereever we left off. If there isn't space, we allocate a new entry
|
||||||
|
* into the pool and copy there */
|
||||||
|
|
||||||
|
struct panfrost_transfer
|
||||||
|
panfrost_allocate_transient(struct panfrost_context *ctx, size_t sz)
|
||||||
|
{
|
||||||
|
/* Pad the size */
|
||||||
|
sz = ALIGN(sz, ALIGNMENT);
|
||||||
|
|
||||||
|
/* Check if there is room in the current entry */
|
||||||
|
struct panfrost_transient_pool *pool = &ctx->transient_pools[ctx->cmdstream_i];
|
||||||
|
|
||||||
|
if ((pool->entry_offset + sz) > pool->entry_size) {
|
||||||
|
/* Don't overflow this entry -- advance to the next */
|
||||||
|
|
||||||
|
pool->entry_offset = 0;
|
||||||
|
|
||||||
|
pool->entry_index++;
|
||||||
|
assert(pool->entry_index < PANFROST_MAX_TRANSIENT_ENTRIES);
|
||||||
|
|
||||||
|
/* Check if this entry exists */
|
||||||
|
|
||||||
|
if (pool->entry_index >= pool->entry_count) {
|
||||||
|
/* Don't overflow the pool -- allocate a new one */
|
||||||
|
struct pipe_context *gallium = (struct pipe_context *) ctx;
|
||||||
|
struct panfrost_screen *screen = panfrost_screen(gallium->screen);
|
||||||
|
struct pb_slab_entry *entry = pb_slab_alloc(&screen->slabs, pool->entry_size, HEAP_TRANSIENT);
|
||||||
|
|
||||||
|
pool->entry_count++;
|
||||||
|
pool->entries[pool->entry_index] = (struct panfrost_memory_entry *) entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we -still- won't overflow */
|
||||||
|
assert(sz < pool->entry_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have an entry we can write to, so do the upload! */
|
||||||
|
struct panfrost_memory_entry *p_entry = pool->entries[pool->entry_index];
|
||||||
|
struct panfrost_memory *backing = (struct panfrost_memory *) p_entry->base.slab;
|
||||||
|
|
||||||
|
struct panfrost_transfer ret = {
|
||||||
|
.cpu = backing->cpu + p_entry->offset + pool->entry_offset,
|
||||||
|
.gpu = backing->gpu + p_entry->offset + pool->entry_offset
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Advance the pointer */
|
||||||
|
pool->entry_offset += sz;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mali_ptr
|
||||||
|
panfrost_upload_transient(struct panfrost_context *ctx, const void *data, size_t sz)
|
||||||
|
{
|
||||||
|
struct panfrost_transfer transfer = panfrost_allocate_transient(ctx, sz);
|
||||||
|
memcpy(transfer.cpu, data, sz);
|
||||||
|
return transfer.gpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: An actual allocator, perhaps
|
||||||
|
// TODO: Multiple stacks for multiple bases?
|
||||||
|
|
||||||
|
int hack_stack_bottom = 4096; /* Don't interfere with constant offsets */
|
||||||
|
int last_offset = 0;
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
pandev_allocate_offset(int *stack, size_t sz)
|
||||||
|
{
|
||||||
|
/* First, align the stack bottom to something nice; it's not critical
|
||||||
|
* at this point if we waste a little space to do so. */
|
||||||
|
|
||||||
|
int excess = *stack & (ALIGNMENT - 1);
|
||||||
|
|
||||||
|
/* Add the secret of my */
|
||||||
|
if (excess)
|
||||||
|
*stack += ALIGNMENT - excess;
|
||||||
|
|
||||||
|
/* Finally, use the new bottom for the allocation and move down the
|
||||||
|
* stack */
|
||||||
|
|
||||||
|
int ret = *stack;
|
||||||
|
*stack += sz;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline mali_ptr
|
||||||
|
pandev_upload(int cheating_offset, int *stack_bottom, mali_ptr base, void *base_map, const void *data, size_t sz, bool no_pad)
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
/* We're not positive about the sizes of all objects, but we don't want
|
||||||
|
* them to crash against each other either. Let the caller disable
|
||||||
|
* padding if they so choose, though. */
|
||||||
|
|
||||||
|
size_t padded_size = no_pad ? sz : sz * 2;
|
||||||
|
|
||||||
|
/* If no specific bottom is specified, use a global one... don't do
|
||||||
|
* this in production, kids */
|
||||||
|
|
||||||
|
if (!stack_bottom)
|
||||||
|
stack_bottom = &hack_stack_bottom;
|
||||||
|
|
||||||
|
/* Allocate space for the new GPU object, if required */
|
||||||
|
|
||||||
|
if (cheating_offset == -1) {
|
||||||
|
offset = pandev_allocate_offset(stack_bottom, padded_size);
|
||||||
|
} else {
|
||||||
|
offset = cheating_offset;
|
||||||
|
*stack_bottom = offset + sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save last offset for sequential uploads (job descriptors) */
|
||||||
|
last_offset = offset + padded_size;
|
||||||
|
|
||||||
|
/* Upload it */
|
||||||
|
memcpy((uint8_t *) base_map + offset, data, sz);
|
||||||
|
|
||||||
|
/* Return the GPU address */
|
||||||
|
return base + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Upload immediately after the last allocation */
|
||||||
|
|
||||||
|
mali_ptr
|
||||||
|
pandev_upload_sequential(mali_ptr base, void *base_map, const void *data, size_t sz)
|
||||||
|
{
|
||||||
|
return pandev_upload(last_offset, NULL, base, base_map, data, sz, /* false */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simplified APIs for the real driver, rather than replays */
|
||||||
|
|
||||||
|
mali_ptr
|
||||||
|
panfrost_upload(struct panfrost_memory *mem, const void *data, size_t sz, bool no_pad)
|
||||||
|
{
|
||||||
|
/* Bounds check */
|
||||||
|
if ((mem->stack_bottom + sz) >= mem->size) {
|
||||||
|
printf("Out of memory, tried to upload %zd but only %zd available\n", sz, mem->size - mem->stack_bottom);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pandev_upload(-1, &mem->stack_bottom, mem->gpu, mem->cpu, data, sz, no_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
mali_ptr
|
||||||
|
panfrost_upload_sequential(struct panfrost_memory *mem, const void *data, size_t sz)
|
||||||
|
{
|
||||||
|
return pandev_upload(last_offset, &mem->stack_bottom, mem->gpu, mem->cpu, data, sz, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simplified interface to allocate a chunk without any upload, to allow
|
||||||
|
* zero-copy uploads. This is particularly useful when the copy would happen
|
||||||
|
* anyway, for instance with texture swizzling. */
|
||||||
|
|
||||||
|
void *
|
||||||
|
panfrost_allocate_transfer(struct panfrost_memory *mem, size_t sz, mali_ptr *gpu)
|
||||||
|
{
|
||||||
|
int offset = pandev_allocate_offset(&mem->stack_bottom, sz);
|
||||||
|
|
||||||
|
*gpu = mem->gpu + offset;
|
||||||
|
return mem->cpu + offset;
|
||||||
|
}
|
||||||
226
src/gallium/drivers/panfrost/pan_assemble.c
Normal file
226
src/gallium/drivers/panfrost/pan_assemble.c
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "pan_context.h"
|
||||||
|
|
||||||
|
#include "compiler/nir/nir.h"
|
||||||
|
#include "nir/tgsi_to_nir.h"
|
||||||
|
#include "midgard/midgard_compile.h"
|
||||||
|
#include "util/u_dynarray.h"
|
||||||
|
|
||||||
|
#include "tgsi/tgsi_dump.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_shader_compile(struct panfrost_context *ctx, struct mali_shader_meta *meta, const char *src, int type, struct panfrost_shader_state *state)
|
||||||
|
{
|
||||||
|
uint8_t *dst;
|
||||||
|
|
||||||
|
nir_shader *s;
|
||||||
|
|
||||||
|
struct pipe_shader_state *cso = state->base;
|
||||||
|
|
||||||
|
if (cso->type == PIPE_SHADER_IR_NIR) {
|
||||||
|
s = nir_shader_clone(NULL, cso->ir.nir);
|
||||||
|
} else {
|
||||||
|
assert (cso->type == PIPE_SHADER_IR_TGSI);
|
||||||
|
//tgsi_dump(cso->tokens, 0);
|
||||||
|
s = tgsi_to_nir(cso->tokens, &midgard_nir_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
s->info.stage = type == JOB_TYPE_VERTEX ? MESA_SHADER_VERTEX : MESA_SHADER_FRAGMENT;
|
||||||
|
|
||||||
|
if (s->info.stage == MESA_SHADER_FRAGMENT) {
|
||||||
|
/* Inject the alpha test now if we need to */
|
||||||
|
|
||||||
|
if (state->alpha_state.enabled) {
|
||||||
|
NIR_PASS_V(s, nir_lower_alpha_test, state->alpha_state.func, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call out to Midgard compiler given the above NIR */
|
||||||
|
|
||||||
|
midgard_program program = {
|
||||||
|
.alpha_ref = state->alpha_state.ref_value
|
||||||
|
};
|
||||||
|
|
||||||
|
midgard_compile_shader_nir(s, &program, false);
|
||||||
|
|
||||||
|
/* Prepare the compiled binary for upload */
|
||||||
|
int size = program.compiled.size;
|
||||||
|
dst = program.compiled.data;
|
||||||
|
|
||||||
|
/* Inject an external shader */
|
||||||
|
#if 0
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
if (type != JOB_TYPE_VERTEX) {
|
||||||
|
FILE *fp = fopen("/home/alyssa/panfrost/midgard/good.bin", "rb");
|
||||||
|
fread(buf, 1, 2816, fp);
|
||||||
|
fclose(fp);
|
||||||
|
dst = buf;
|
||||||
|
size = 2816;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Upload the shader. The lookahead tag is ORed on as a tagged pointer.
|
||||||
|
* I bet someone just thought that would be a cute pun. At least,
|
||||||
|
* that's how I'd do it. */
|
||||||
|
|
||||||
|
meta->shader = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag;
|
||||||
|
|
||||||
|
util_dynarray_fini(&program.compiled);
|
||||||
|
|
||||||
|
meta->midgard1.uniform_count = MIN2(program.uniform_count, program.uniform_cutoff);
|
||||||
|
meta->attribute_count = program.attribute_count;
|
||||||
|
meta->varying_count = program.varying_count;
|
||||||
|
meta->midgard1.work_count = program.work_register_count;
|
||||||
|
|
||||||
|
state->can_discard = program.can_discard;
|
||||||
|
state->writes_point_size = program.writes_point_size;
|
||||||
|
|
||||||
|
/* Separate as primary uniform count is truncated */
|
||||||
|
state->uniform_count = program.uniform_count;
|
||||||
|
|
||||||
|
/* gl_Position eats up an extra spot */
|
||||||
|
if (type == JOB_TYPE_VERTEX)
|
||||||
|
meta->varying_count += 1;
|
||||||
|
|
||||||
|
/* gl_FragCoord does -not- eat an extra spot; it will be included in our count if we need it */
|
||||||
|
|
||||||
|
|
||||||
|
meta->midgard1.unknown2 = 8; /* XXX */
|
||||||
|
|
||||||
|
/* Varyings are known only through the shader. We choose to upload this
|
||||||
|
* information with the vertex shader, though the choice is perhaps
|
||||||
|
* arbitrary */
|
||||||
|
|
||||||
|
if (type == JOB_TYPE_VERTEX) {
|
||||||
|
struct panfrost_varyings *varyings = &state->varyings;
|
||||||
|
|
||||||
|
/* Measured in vec4 words. Don't include gl_Position */
|
||||||
|
int varying_count = program.varying_count;
|
||||||
|
|
||||||
|
/* Setup two buffers, one for position, the other for normal
|
||||||
|
* varyings, as seen in traces. TODO: Are there other
|
||||||
|
* configurations we might use? */
|
||||||
|
|
||||||
|
varyings->varying_buffer_count = 2;
|
||||||
|
|
||||||
|
/* mediump vec4s sequentially */
|
||||||
|
varyings->varyings_stride[0] = (2 * sizeof(float)) * varying_count;
|
||||||
|
|
||||||
|
/* highp gl_Position */
|
||||||
|
varyings->varyings_stride[1] = 4 * sizeof(float);
|
||||||
|
|
||||||
|
/* mediump gl_PointSize */
|
||||||
|
if (program.writes_point_size) {
|
||||||
|
++varyings->varying_buffer_count;
|
||||||
|
varyings->varyings_stride[2] = 2; /* sizeof(fp16) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup gl_Position, its weirdo analogue, and gl_PointSize (optionally) */
|
||||||
|
unsigned default_vec1_swizzle = panfrost_get_default_swizzle(1);
|
||||||
|
unsigned default_vec4_swizzle = panfrost_get_default_swizzle(4);
|
||||||
|
|
||||||
|
struct mali_attr_meta vertex_special_varyings[] = {
|
||||||
|
{
|
||||||
|
.index = 1,
|
||||||
|
.format = MALI_VARYING_POS,
|
||||||
|
|
||||||
|
.swizzle = default_vec4_swizzle,
|
||||||
|
.unknown1 = 0x2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.index = 1,
|
||||||
|
.format = MALI_RGBA16F,
|
||||||
|
|
||||||
|
/* TODO: Wat? yyyy swizzle? */
|
||||||
|
.swizzle = 0x249,
|
||||||
|
.unknown1 = 0x0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.index = 2,
|
||||||
|
.format = MALI_R16F,
|
||||||
|
.swizzle = default_vec1_swizzle,
|
||||||
|
.unknown1 = 0x2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* How many special vertex varyings are actually required? */
|
||||||
|
int vertex_special_count = 2 + (program.writes_point_size ? 1 : 0);
|
||||||
|
|
||||||
|
/* Setup actual varyings. XXX: Don't assume vec4 */
|
||||||
|
|
||||||
|
struct mali_attr_meta mali_varyings[PIPE_MAX_ATTRIBS];
|
||||||
|
|
||||||
|
for (int i = 0; i < varying_count; ++i) {
|
||||||
|
struct mali_attr_meta vec4_varying_meta = {
|
||||||
|
.index = 0,
|
||||||
|
.format = MALI_RGBA16F,
|
||||||
|
.swizzle = default_vec4_swizzle,
|
||||||
|
.unknown1 = 0x2,
|
||||||
|
|
||||||
|
/* Set offset to keep everything back-to-back in
|
||||||
|
* the same buffer */
|
||||||
|
.src_offset = 8 * i,
|
||||||
|
};
|
||||||
|
|
||||||
|
mali_varyings[i] = vec4_varying_meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't count the weirdo gl_Position in our varying count */
|
||||||
|
varyings->varying_count = varying_count - 1;
|
||||||
|
|
||||||
|
/* In this context, position_meta represents the implicit
|
||||||
|
* gl_FragCoord varying. So, upload all the varyings */
|
||||||
|
|
||||||
|
unsigned varyings_size = sizeof(struct mali_attr_meta) * varyings->varying_count;
|
||||||
|
unsigned vertex_special_size = sizeof(struct mali_attr_meta) * vertex_special_count;
|
||||||
|
unsigned vertex_size = vertex_special_size + varyings_size;
|
||||||
|
unsigned fragment_size = varyings_size + sizeof(struct mali_attr_meta);
|
||||||
|
|
||||||
|
struct panfrost_transfer transfer = panfrost_allocate_chunk(ctx, vertex_size + fragment_size, HEAP_DESCRIPTOR);
|
||||||
|
|
||||||
|
/* Copy varyings in the follow order:
|
||||||
|
* - Position 1, 2
|
||||||
|
* - Varyings 1, 2, ..., n
|
||||||
|
* - Varyings 1, 2, ..., n (duplicate)
|
||||||
|
* - Position 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
memcpy(transfer.cpu, vertex_special_varyings, vertex_special_size);
|
||||||
|
memcpy(transfer.cpu + vertex_special_size, mali_varyings, varyings_size);
|
||||||
|
memcpy(transfer.cpu + vertex_size, mali_varyings, varyings_size);
|
||||||
|
memcpy(transfer.cpu + vertex_size + varyings_size, &vertex_special_varyings[0], sizeof(struct mali_attr_meta));
|
||||||
|
|
||||||
|
/* Point to the descriptor */
|
||||||
|
varyings->varyings_buffer_cpu = transfer.cpu;
|
||||||
|
varyings->varyings_descriptor = transfer.gpu;
|
||||||
|
varyings->varyings_descriptor_fragment = transfer.gpu + vertex_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
178
src/gallium/drivers/panfrost/pan_blend_shaders.c
Normal file
178
src/gallium/drivers/panfrost/pan_blend_shaders.c
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "pan_blend_shaders.h"
|
||||||
|
#include "midgard/midgard_compile.h"
|
||||||
|
#include "compiler/nir/nir_builder.h"
|
||||||
|
//#include "gallium/auxiliary/nir/nir_lower_blend.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implements the command stream portion of programmatic blend shaders.
|
||||||
|
*
|
||||||
|
* On Midgard, common blending operations are accelerated by the fixed-function
|
||||||
|
* blending pipeline. Panfrost supports this fast path via the code in
|
||||||
|
* pan_blending.c. Nevertheless, uncommon blend modes (including some seemingly
|
||||||
|
* simple modes present in ES2) require "blend shaders", a special internal
|
||||||
|
* shader type used for programmable blending.
|
||||||
|
*
|
||||||
|
* Blend shaders operate during the normal blending time, but they bypass the
|
||||||
|
* fixed-function blending pipeline and instead go straight to the Midgard
|
||||||
|
* shader cores. The shaders themselves are essentially just fragment shaders,
|
||||||
|
* making heavy use of uint8 arithmetic to manipulate RGB values for the
|
||||||
|
* framebuffer.
|
||||||
|
*
|
||||||
|
* As is typical with Midgard, shader binaries must be accompanied by
|
||||||
|
* information about the first tag (ORed with the bottom nibble of address,
|
||||||
|
* like usual) and work registers. Work register count is specified in the
|
||||||
|
* blend descriptor, as well as in the coresponding fragment shader's work
|
||||||
|
* count. This suggests that blend shader invocation is tied to fragment shader
|
||||||
|
* execution.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* As for blend shaders, they use the standard ISA.
|
||||||
|
*
|
||||||
|
* The source pixel colour, including alpha, is preloaded into r0 as a vec4 of
|
||||||
|
* float32.
|
||||||
|
*
|
||||||
|
* The destination pixel colour must be loaded explicitly via load/store ops.
|
||||||
|
* TODO: Investigate.
|
||||||
|
*
|
||||||
|
* They use fragment shader writeout; however, instead of writing a vec4 of
|
||||||
|
* float32 for RGBA encoding, we writeout a vec4 of uint8, using 8-bit imov
|
||||||
|
* instead of 32-bit fmov. The net result is that r0 encodes a single uint32
|
||||||
|
* containing all four channels of the color. Accordingly, the blend shader
|
||||||
|
* epilogue has to scale all four channels by 255 and then type convert to a
|
||||||
|
* uint8.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
*
|
||||||
|
* Blend shaders hardcode constants. Naively, this requires recompilation each
|
||||||
|
* time the blend color changes, which is a performance risk. Accordingly, we
|
||||||
|
* 'cheat' a bit: instead of loading the constant, we compile a shader with a
|
||||||
|
* dummy constant, exporting the offset to the immediate in the shader binary,
|
||||||
|
* storing this generic binary and metadata in the CSO itself at CSO create
|
||||||
|
* time.
|
||||||
|
*
|
||||||
|
* We then hot patch in the color into this shader at attachment / color change
|
||||||
|
* time, allowing for CSO create to be the only expensive operation
|
||||||
|
* (compilation).
|
||||||
|
*/
|
||||||
|
|
||||||
|
static nir_ssa_def *
|
||||||
|
nir_blending_f(const struct pipe_rt_blend_state *blend, nir_builder *b,
|
||||||
|
nir_ssa_def *s_src, nir_ssa_def *s_dst, nir_ssa_def *s_con)
|
||||||
|
{
|
||||||
|
/* Stub, to be replaced by the real implementation when that is
|
||||||
|
* upstream (pending on a rewrite to be Gallium agnostic) */
|
||||||
|
|
||||||
|
return s_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_make_blend_shader(struct panfrost_context *ctx, struct panfrost_blend_state *cso, const struct pipe_blend_color *blend_color)
|
||||||
|
{
|
||||||
|
const struct pipe_rt_blend_state *blend = &cso->base.rt[0];
|
||||||
|
mali_ptr *out = &cso->blend_shader;
|
||||||
|
|
||||||
|
/* Build the shader */
|
||||||
|
|
||||||
|
nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
|
||||||
|
nir_function *fn = nir_function_create(shader, "main");
|
||||||
|
nir_function_impl *impl = nir_function_impl_create(fn);
|
||||||
|
|
||||||
|
/* Create the blend variables */
|
||||||
|
|
||||||
|
nir_variable *c_src = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_Color");
|
||||||
|
nir_variable *c_dst = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_SecondaryColor");
|
||||||
|
nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_FragColor");
|
||||||
|
nir_variable *c_con = nir_variable_create(shader, nir_var_uniform, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "constant");
|
||||||
|
|
||||||
|
c_src->data.location = VARYING_SLOT_COL0;
|
||||||
|
c_dst->data.location = VARYING_SLOT_COL1;
|
||||||
|
c_out->data.location = FRAG_RESULT_COLOR;
|
||||||
|
|
||||||
|
/* Setup nir_builder */
|
||||||
|
|
||||||
|
nir_builder _b;
|
||||||
|
nir_builder *b = &_b;
|
||||||
|
nir_builder_init(b, impl);
|
||||||
|
b->cursor = nir_before_block(nir_start_block(impl));
|
||||||
|
|
||||||
|
/* Setup inputs */
|
||||||
|
|
||||||
|
nir_ssa_def *s_src = nir_load_var(b, c_src);
|
||||||
|
nir_ssa_def *s_dst = nir_load_var(b, c_dst);
|
||||||
|
nir_ssa_def *s_con = nir_load_var(b, c_con);
|
||||||
|
|
||||||
|
/* Build a trivial blend shader */
|
||||||
|
nir_store_var(b, c_out, nir_blending_f(blend, b, s_src, s_dst, s_con), 0xFF);
|
||||||
|
|
||||||
|
nir_print_shader(shader, stdout);
|
||||||
|
|
||||||
|
/* Compile the built shader */
|
||||||
|
|
||||||
|
midgard_program program;
|
||||||
|
midgard_compile_shader_nir(shader, &program, true);
|
||||||
|
|
||||||
|
|
||||||
|
/* Upload the shader */
|
||||||
|
|
||||||
|
int size = program.compiled.size;
|
||||||
|
uint8_t *dst = program.compiled.data;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
midgard_program program = {
|
||||||
|
.work_register_count = 3,
|
||||||
|
.first_tag = 9,
|
||||||
|
//.blend_patch_offset = 16
|
||||||
|
.blend_patch_offset = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
char dst[4096];
|
||||||
|
|
||||||
|
FILE *fp = fopen("/home/alyssa/panfrost/midgard/blend.bin", "rb");
|
||||||
|
fread(dst, 1, 2816, fp);
|
||||||
|
fclose(fp);
|
||||||
|
int size = 2816;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Hot patch in constant color */
|
||||||
|
|
||||||
|
if (program.blend_patch_offset >= 0) {
|
||||||
|
float *hot_color = (float *) (dst + program.blend_patch_offset);
|
||||||
|
|
||||||
|
for (int c = 0; c < 4; ++c)
|
||||||
|
hot_color[c] = blend_color->color[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag;
|
||||||
|
|
||||||
|
/* We need to switch to shader mode */
|
||||||
|
cso->has_blend_shader = true;
|
||||||
|
|
||||||
|
/* At least two work registers are needed due to an encoding quirk */
|
||||||
|
cso->blend_work_count = MAX2(program.work_register_count, 2);
|
||||||
|
}
|
||||||
36
src/gallium/drivers/panfrost/pan_blend_shaders.h
Normal file
36
src/gallium/drivers/panfrost/pan_blend_shaders.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PAN_BLEND_SHADERS_H__
|
||||||
|
#define __PAN_BLEND_SHADERS_H__
|
||||||
|
|
||||||
|
#include "pipe/p_state.h"
|
||||||
|
#include "pipe/p_defines.h"
|
||||||
|
#include <panfrost-job.h>
|
||||||
|
#include "pan_context.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_make_blend_shader(struct panfrost_context *ctx, struct panfrost_blend_state *cso, const struct pipe_blend_color *blend_color);
|
||||||
|
|
||||||
|
#endif
|
||||||
401
src/gallium/drivers/panfrost/pan_blending.c
Normal file
401
src/gallium/drivers/panfrost/pan_blending.c
Normal file
|
|
@ -0,0 +1,401 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "pan_blending.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implements fixed-function blending on Midgard.
|
||||||
|
*
|
||||||
|
* Midgard splits blending into a fixed-function fast path and a programmable
|
||||||
|
* slow path. The fixed function blending architecture is based on "dominant"
|
||||||
|
* blend factors. Blending is encoded separately (but identically) between RGB
|
||||||
|
* and alpha functions.
|
||||||
|
*
|
||||||
|
* Essentially, for a given blending operation, there is a single dominant
|
||||||
|
* factor. The following dominant factors are possible:
|
||||||
|
*
|
||||||
|
* - zero
|
||||||
|
* - source color
|
||||||
|
* - destination color
|
||||||
|
* - source alpha
|
||||||
|
* - destination alpha
|
||||||
|
* - constant float
|
||||||
|
*
|
||||||
|
* Further, a dominant factor's arithmetic compliment could be used. For
|
||||||
|
* instance, to encode GL_ONE_MINUS_SOURCE_ALPHA, the dominant factor would be
|
||||||
|
* MALI_DOMINANT_SRC_ALPHA with the complement_dominant bit set.
|
||||||
|
*
|
||||||
|
* A single constant float can be passed to the fixed-function hardware,
|
||||||
|
* allowing CONSTANT_ALPHA support. Further, if all components of the constant
|
||||||
|
* glBlendColor are identical, CONSTANT_COLOR can be implemented with the
|
||||||
|
* constant float mode. If the components differ, programmable blending is
|
||||||
|
* required.
|
||||||
|
*
|
||||||
|
* The nondominant factor can be either:
|
||||||
|
*
|
||||||
|
* - the same as the dominant factor (MALI_BLEND_NON_MIRROR)
|
||||||
|
* - zero (MALI_BLEND_NON_ZERO)
|
||||||
|
*
|
||||||
|
* Exactly one of the blend operation's source or destination can be used as
|
||||||
|
* the dominant factor; this is selected by the
|
||||||
|
* MALI_BLEND_DOM_SOURCE/DESTINATION flag.
|
||||||
|
*
|
||||||
|
* By default, all blending follows the standard OpenGL addition equation:
|
||||||
|
*
|
||||||
|
* out = source_value * source_factor + destination_value * destination_factor
|
||||||
|
*
|
||||||
|
* By setting the negate_source or negate_dest bits, other blend functions can
|
||||||
|
* be created. For instance, for SUBTRACT mode, set the "negate destination"
|
||||||
|
* flag, and similarly for REVERSE_SUBTRACT with "negate source".
|
||||||
|
*
|
||||||
|
* Finally, there is a "clip modifier" controlling the final blending
|
||||||
|
* behaviour, allowing for the following modes:
|
||||||
|
*
|
||||||
|
* - normal
|
||||||
|
* - force source factor to one (MALI_BLEND_MODE_SOURCE_ONE)
|
||||||
|
* - force destination factor to one (MALI_BLEND_MODE_DEST_ONE)
|
||||||
|
*
|
||||||
|
* The clipping flags can be used to encode blend modes where the nondominant
|
||||||
|
* factor is ONE.
|
||||||
|
*
|
||||||
|
* As an example putting it all together, to encode the following blend state:
|
||||||
|
*
|
||||||
|
* glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||||
|
* glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE);
|
||||||
|
*
|
||||||
|
* We need the following configuration:
|
||||||
|
*
|
||||||
|
* - negate source (for REVERSE_SUBTRACT)
|
||||||
|
* - dominant factor "source alpha"
|
||||||
|
* - compliment dominant
|
||||||
|
* - source dominant
|
||||||
|
* - force destination to ONE
|
||||||
|
*
|
||||||
|
* The following routines implement this fixed function blending encoding
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Helper to find the uncomplemented Gallium blend factor corresponding to a
|
||||||
|
* complemented Gallium blend factor */
|
||||||
|
|
||||||
|
static int
|
||||||
|
complement_factor(int factor)
|
||||||
|
{
|
||||||
|
switch (factor) {
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||||
|
return PIPE_BLENDFACTOR_SRC_COLOR;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||||
|
return PIPE_BLENDFACTOR_SRC_ALPHA;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||||
|
return PIPE_BLENDFACTOR_DST_ALPHA;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||||
|
return PIPE_BLENDFACTOR_DST_COLOR;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
|
||||||
|
return PIPE_BLENDFACTOR_CONST_COLOR;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
|
||||||
|
return PIPE_BLENDFACTOR_CONST_ALPHA;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper to strip the complement from any Gallium blend factor */
|
||||||
|
|
||||||
|
static int
|
||||||
|
uncomplement_factor(int factor)
|
||||||
|
{
|
||||||
|
int complement = complement_factor(factor);
|
||||||
|
return (complement == -1) ? factor : complement;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Attempt to find the dominant factor given a particular factor, complementing
|
||||||
|
* as necessary */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
panfrost_make_dominant_factor(unsigned src_factor, enum mali_dominant_factor *factor, bool *invert)
|
||||||
|
{
|
||||||
|
switch (src_factor) {
|
||||||
|
case PIPE_BLENDFACTOR_SRC_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||||
|
*factor = MALI_DOMINANT_SRC_COLOR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_SRC_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||||
|
*factor = MALI_DOMINANT_SRC_ALPHA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_DST_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||||
|
*factor = MALI_DOMINANT_DST_COLOR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_DST_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||||
|
*factor = MALI_DOMINANT_DST_ALPHA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_ONE:
|
||||||
|
case PIPE_BLENDFACTOR_ZERO:
|
||||||
|
*factor = MALI_DOMINANT_ZERO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIPE_BLENDFACTOR_CONST_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_CONST_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
|
||||||
|
*factor = MALI_DOMINANT_CONSTANT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Fancy blend modes not supported */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set invert flags */
|
||||||
|
|
||||||
|
switch (src_factor) {
|
||||||
|
case PIPE_BLENDFACTOR_ONE:
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
|
||||||
|
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
|
||||||
|
case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
|
||||||
|
*invert = true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this is a special edge case blend factor, which may require the use
|
||||||
|
* of clip modifiers */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_edge_blendfactor(unsigned factor)
|
||||||
|
{
|
||||||
|
return factor == PIPE_BLENDFACTOR_ONE || factor == PIPE_BLENDFACTOR_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the actual fixed function encoding. Encode the function with negate
|
||||||
|
* bits. Check for various cases to work out the dominant/nondominant split and
|
||||||
|
* accompanying flags. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
panfrost_make_fixed_blend_part(unsigned func, unsigned src_factor, unsigned dst_factor, unsigned *out)
|
||||||
|
{
|
||||||
|
struct mali_blend_mode part = { 0 };
|
||||||
|
|
||||||
|
/* Make sure that the blend function is representible with negate flags */
|
||||||
|
|
||||||
|
if (func == PIPE_BLEND_ADD) {
|
||||||
|
/* Default, no modifiers needed */
|
||||||
|
} else if (func == PIPE_BLEND_SUBTRACT)
|
||||||
|
part.negate_dest = true;
|
||||||
|
else if (func == PIPE_BLEND_REVERSE_SUBTRACT)
|
||||||
|
part.negate_source = true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
part.clip_modifier = MALI_BLEND_MOD_NORMAL;
|
||||||
|
|
||||||
|
/* Decide which is dominant, source or destination. If one is an edge
|
||||||
|
* case, use the other as a factor. If they're the same, it doesn't
|
||||||
|
* matter; we just mirror. If they're different non-edge-cases, you
|
||||||
|
* need a blend shader (don't do that). */
|
||||||
|
|
||||||
|
if (is_edge_blendfactor(dst_factor)) {
|
||||||
|
part.dominant = MALI_BLEND_DOM_SOURCE;
|
||||||
|
part.nondominant_mode = MALI_BLEND_NON_ZERO;
|
||||||
|
|
||||||
|
if (dst_factor == PIPE_BLENDFACTOR_ONE)
|
||||||
|
part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
|
||||||
|
} else if (is_edge_blendfactor(src_factor)) {
|
||||||
|
part.dominant = MALI_BLEND_DOM_DESTINATION;
|
||||||
|
part.nondominant_mode = MALI_BLEND_NON_ZERO;
|
||||||
|
|
||||||
|
if (src_factor == PIPE_BLENDFACTOR_ONE)
|
||||||
|
part.clip_modifier = MALI_BLEND_MOD_SOURCE_ONE;
|
||||||
|
|
||||||
|
} else if (src_factor == dst_factor) {
|
||||||
|
part.dominant = MALI_BLEND_DOM_DESTINATION; /* Ought to be an arbitrary choice, but we need to set destination for some reason? Align with the blob until we understand more */
|
||||||
|
part.nondominant_mode = MALI_BLEND_NON_MIRROR;
|
||||||
|
} else if (src_factor == complement_factor(dst_factor)) {
|
||||||
|
/* TODO: How does this work exactly? */
|
||||||
|
part.dominant = MALI_BLEND_DOM_SOURCE;
|
||||||
|
part.nondominant_mode = MALI_BLEND_NON_MIRROR;
|
||||||
|
part.clip_modifier = MALI_BLEND_MOD_DEST_ONE;
|
||||||
|
} else if (dst_factor == complement_factor(src_factor)) {
|
||||||
|
part.dominant = MALI_BLEND_DOM_SOURCE;
|
||||||
|
part.nondominant_mode = MALI_BLEND_NON_MIRROR;
|
||||||
|
part.clip_modifier = /*MALI_BLEND_MOD_SOURCE_ONE*/MALI_BLEND_MOD_DEST_ONE; /* Which modifier should it be? */
|
||||||
|
} else {
|
||||||
|
printf("Failed to find dominant factor?\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned in_dominant_factor =
|
||||||
|
part.dominant == MALI_BLEND_DOM_SOURCE ? src_factor : dst_factor;
|
||||||
|
|
||||||
|
if (part.clip_modifier == MALI_BLEND_MOD_NORMAL && in_dominant_factor == PIPE_BLENDFACTOR_ONE) {
|
||||||
|
part.clip_modifier = part.dominant == MALI_BLEND_DOM_SOURCE ? MALI_BLEND_MOD_SOURCE_ONE : MALI_BLEND_MOD_DEST_ONE;
|
||||||
|
in_dominant_factor = PIPE_BLENDFACTOR_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool invert_dominant = false;
|
||||||
|
enum mali_dominant_factor dominant_factor;
|
||||||
|
|
||||||
|
if (!panfrost_make_dominant_factor(in_dominant_factor, &dominant_factor, &invert_dominant))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
part.dominant_factor = dominant_factor;
|
||||||
|
part.complement_dominant = invert_dominant;
|
||||||
|
|
||||||
|
/* Write out mode */
|
||||||
|
memcpy(out, &part, sizeof(part));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can upload a single constant for all of the factors. So, scan the factors
|
||||||
|
* for constants used, and scan the constants for the constants used. If there
|
||||||
|
* is a single unique constant, output that. If there are multiple,
|
||||||
|
* fixed-function operation breaks down. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
panfrost_make_constant(unsigned *factors, unsigned num_factors, const struct pipe_blend_color *blend_color, float *out)
|
||||||
|
{
|
||||||
|
/* Color components used */
|
||||||
|
bool cc[4] = { false };
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < num_factors; ++i) {
|
||||||
|
unsigned factor = uncomplement_factor(factors[i]);
|
||||||
|
|
||||||
|
if (factor == PIPE_BLENDFACTOR_CONST_COLOR)
|
||||||
|
cc[0] = cc[1] = cc[2] = true;
|
||||||
|
else if (factor == PIPE_BLENDFACTOR_CONST_ALPHA)
|
||||||
|
cc[3] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the actual constant associated with the components used*/
|
||||||
|
|
||||||
|
float constant = 0.0;
|
||||||
|
bool has_constant = false;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 4; ++i) {
|
||||||
|
/* If the component is unused, nothing to do */
|
||||||
|
if (!cc[i]) continue;
|
||||||
|
|
||||||
|
float value = blend_color->color[i];
|
||||||
|
|
||||||
|
/* Either there's a second constant, in which case we fail, or
|
||||||
|
* there's no constant / a first constant, in which case we use
|
||||||
|
* that constant */
|
||||||
|
|
||||||
|
if (has_constant && constant != value) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
has_constant = true;
|
||||||
|
constant = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have the constant -- success! */
|
||||||
|
|
||||||
|
*out = constant;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the descriptor for a fixed blend mode given the corresponding Gallium
|
||||||
|
* state, if possible. Return true and write out the blend descriptor into
|
||||||
|
* blend_equation. If it is not possible with the fixed function
|
||||||
|
* representating, return false to handle degenerate cases with a blend shader
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct pipe_rt_blend_state default_blend = {
|
||||||
|
.blend_enable = 1,
|
||||||
|
|
||||||
|
.rgb_func = PIPE_BLEND_ADD,
|
||||||
|
.rgb_src_factor = PIPE_BLENDFACTOR_ONE,
|
||||||
|
.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO,
|
||||||
|
|
||||||
|
.alpha_func = PIPE_BLEND_ADD,
|
||||||
|
.alpha_src_factor = PIPE_BLENDFACTOR_ONE,
|
||||||
|
.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO,
|
||||||
|
|
||||||
|
.colormask = PIPE_MASK_RGBA
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state *blend, struct mali_blend_equation *out, unsigned colormask, const struct pipe_blend_color *blend_color)
|
||||||
|
{
|
||||||
|
/* If no blending is enabled, default back on `replace` mode */
|
||||||
|
|
||||||
|
if (!blend->blend_enable)
|
||||||
|
return panfrost_make_fixed_blend_mode(&default_blend, out, colormask, blend_color);
|
||||||
|
|
||||||
|
/* We have room only for a single float32 constant between the four
|
||||||
|
* components. If we need more, spill to the programmable pipeline. */
|
||||||
|
|
||||||
|
unsigned factors[] = {
|
||||||
|
blend->rgb_src_factor, blend->rgb_dst_factor,
|
||||||
|
blend->alpha_src_factor, blend->alpha_dst_factor,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!panfrost_make_constant(factors, ARRAY_SIZE(factors), blend_color, &out->constant))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned rgb_mode = 0;
|
||||||
|
unsigned alpha_mode = 0;
|
||||||
|
|
||||||
|
if (!panfrost_make_fixed_blend_part(
|
||||||
|
blend->rgb_func, blend->rgb_src_factor, blend->rgb_dst_factor,
|
||||||
|
&rgb_mode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!panfrost_make_fixed_blend_part(
|
||||||
|
blend->alpha_func, blend->alpha_src_factor, blend->alpha_dst_factor,
|
||||||
|
&alpha_mode))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out->rgb_mode = rgb_mode;
|
||||||
|
out->alpha_mode = alpha_mode;
|
||||||
|
|
||||||
|
/* Gallium and Mali represent colour masks identically. XXX: Static assert for future proof */
|
||||||
|
out->color_mask = colormask;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
34
src/gallium/drivers/panfrost/pan_blending.h
Normal file
34
src/gallium/drivers/panfrost/pan_blending.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PAN_BLENDING_H__
|
||||||
|
#define __PAN_BLENDING_H__
|
||||||
|
|
||||||
|
#include "pipe/p_state.h"
|
||||||
|
#include "pipe/p_defines.h"
|
||||||
|
#include <panfrost-job.h>
|
||||||
|
|
||||||
|
bool panfrost_make_fixed_blend_mode(const struct pipe_rt_blend_state *blend, struct mali_blend_equation *out, unsigned colormask, const struct pipe_blend_color *blend_color);
|
||||||
|
|
||||||
|
#endif
|
||||||
2698
src/gallium/drivers/panfrost/pan_context.c
Normal file
2698
src/gallium/drivers/panfrost/pan_context.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -356,6 +356,9 @@ panfrost_flush(
|
||||||
struct pipe_fence_handle **fence,
|
struct pipe_fence_handle **fence,
|
||||||
unsigned flags);
|
unsigned flags);
|
||||||
|
|
||||||
|
mali_ptr
|
||||||
|
panfrost_fragment_job(struct panfrost_context *ctx);
|
||||||
|
|
||||||
void
|
void
|
||||||
panfrost_shader_compile(struct panfrost_context *ctx, struct mali_shader_meta *meta, const char *src, int type, struct panfrost_shader_state *state);
|
panfrost_shader_compile(struct panfrost_context *ctx, struct mali_shader_meta *meta, const char *src, int type, struct panfrost_shader_state *state);
|
||||||
|
|
||||||
|
|
|
||||||
42
src/gallium/drivers/panfrost/pan_drm.c
Normal file
42
src/gallium/drivers/panfrost/pan_drm.c
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2019 Collabora, Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "util/u_memory.h"
|
||||||
|
|
||||||
|
#include "pan_screen.h"
|
||||||
|
#include "pan_drm.h"
|
||||||
|
|
||||||
|
struct panfrost_drm {
|
||||||
|
struct panfrost_driver base;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct panfrost_driver *
|
||||||
|
panfrost_create_drm_driver(int fd)
|
||||||
|
{
|
||||||
|
struct panfrost_drm *driver = CALLOC_STRUCT(panfrost_drm);
|
||||||
|
|
||||||
|
driver->fd = fd;
|
||||||
|
|
||||||
|
return &driver->base;
|
||||||
|
}
|
||||||
32
src/gallium/drivers/panfrost/pan_drm.h
Normal file
32
src/gallium/drivers/panfrost/pan_drm.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2019 Collabora, Ltd.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PAN_DRM_H__
|
||||||
|
#define __PAN_DRM_H__
|
||||||
|
|
||||||
|
#include "pan_screen.h"
|
||||||
|
|
||||||
|
struct panfrost_driver *panfrost_create_drm_driver(int fd);
|
||||||
|
|
||||||
|
#endif /* __PAN_DRM_H__ */
|
||||||
220
src/gallium/drivers/panfrost/pan_format.c
Normal file
220
src/gallium/drivers/panfrost/pan_format.c
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pan_format.h"
|
||||||
|
|
||||||
|
/* From panwrap/panwrap-decoder, but we don't want to bring in all those headers */
|
||||||
|
char *panwrap_format_name(enum mali_format format);
|
||||||
|
|
||||||
|
/* Construct a default swizzle based on the number of components */
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
panfrost_translate_swizzle(enum pipe_swizzle s)
|
||||||
|
{
|
||||||
|
switch (s) {
|
||||||
|
case PIPE_SWIZZLE_X:
|
||||||
|
return MALI_CHANNEL_RED;
|
||||||
|
|
||||||
|
case PIPE_SWIZZLE_Y:
|
||||||
|
return MALI_CHANNEL_GREEN;
|
||||||
|
|
||||||
|
case PIPE_SWIZZLE_Z:
|
||||||
|
return MALI_CHANNEL_BLUE;
|
||||||
|
|
||||||
|
case PIPE_SWIZZLE_W:
|
||||||
|
return MALI_CHANNEL_ALPHA;
|
||||||
|
|
||||||
|
case PIPE_SWIZZLE_0:
|
||||||
|
case PIPE_SWIZZLE_NONE:
|
||||||
|
return MALI_CHANNEL_ZERO;
|
||||||
|
|
||||||
|
case PIPE_SWIZZLE_1:
|
||||||
|
return MALI_CHANNEL_ONE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Translate a Gallium swizzle quad to a 12-bit Mali swizzle code */
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
panfrost_translate_swizzle_4(const unsigned char swizzle[4])
|
||||||
|
{
|
||||||
|
unsigned out = 0;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 4; ++i) {
|
||||||
|
unsigned translated = panfrost_translate_swizzle(swizzle[i]);
|
||||||
|
out |= (translated << (3*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
panfrost_get_default_swizzle(unsigned components)
|
||||||
|
{
|
||||||
|
unsigned char default_swizzles[4][4] = {
|
||||||
|
{PIPE_SWIZZLE_X, PIPE_SWIZZLE_0, PIPE_SWIZZLE_0, PIPE_SWIZZLE_1},
|
||||||
|
{PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_0, PIPE_SWIZZLE_1},
|
||||||
|
{PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_1},
|
||||||
|
{PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(components >= 1 && components <= 4);
|
||||||
|
return panfrost_translate_swizzle_4(default_swizzles[components - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
panfrost_translate_channel_width(unsigned size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case 8:
|
||||||
|
return MALI_CHANNEL_8;
|
||||||
|
case 16:
|
||||||
|
return MALI_CHANNEL_16;
|
||||||
|
case 32:
|
||||||
|
return MALI_CHANNEL_32;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown width %d\n", size);
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
panfrost_translate_channel_type(unsigned type, unsigned size, bool norm) {
|
||||||
|
switch (type) {
|
||||||
|
case UTIL_FORMAT_TYPE_UNSIGNED:
|
||||||
|
return norm ? MALI_FORMAT_UNORM : MALI_FORMAT_UINT;
|
||||||
|
|
||||||
|
case UTIL_FORMAT_TYPE_SIGNED:
|
||||||
|
return norm ? MALI_FORMAT_SNORM : MALI_FORMAT_SINT;
|
||||||
|
|
||||||
|
case UTIL_FORMAT_TYPE_FLOAT:
|
||||||
|
if (size == 16) {
|
||||||
|
/* With FLOAT, fp16 */
|
||||||
|
return MALI_FORMAT_SINT;
|
||||||
|
} else if (size == 32) {
|
||||||
|
/* With FLOAT< fp32 */
|
||||||
|
return MALI_FORMAT_UNORM;
|
||||||
|
} else {
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constructs a mali_format satisfying the specified Gallium format
|
||||||
|
* description */
|
||||||
|
|
||||||
|
enum mali_format
|
||||||
|
panfrost_find_format(const struct util_format_description *desc)
|
||||||
|
{
|
||||||
|
/* Find first non-VOID channel */
|
||||||
|
struct util_format_channel_description chan = desc->channel[0];
|
||||||
|
|
||||||
|
for (unsigned c = 0; c < 4; ++c) {
|
||||||
|
if (desc->channel[c].type == UTIL_FORMAT_TYPE_VOID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chan = desc->channel[c];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for special formats */
|
||||||
|
switch (desc->format) {
|
||||||
|
case PIPE_FORMAT_YV12:
|
||||||
|
case PIPE_FORMAT_YV16:
|
||||||
|
case PIPE_FORMAT_IYUV:
|
||||||
|
case PIPE_FORMAT_NV21:
|
||||||
|
fprintf(stderr, "YUV format type %s (%d) is not yet supported, but it's probably close to NV12!\n", desc->name, desc->format);
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIPE_FORMAT_NV12:
|
||||||
|
return MALI_NV12;
|
||||||
|
|
||||||
|
case PIPE_FORMAT_R10G10B10X2_UNORM:
|
||||||
|
case PIPE_FORMAT_B10G10R10X2_UNORM:
|
||||||
|
case PIPE_FORMAT_R10G10B10A2_UNORM:
|
||||||
|
case PIPE_FORMAT_B10G10R10A2_UNORM:
|
||||||
|
return MALI_RGB10_A2_UNORM;
|
||||||
|
|
||||||
|
case PIPE_FORMAT_R10G10B10X2_SNORM:
|
||||||
|
case PIPE_FORMAT_R10G10B10A2_SNORM:
|
||||||
|
case PIPE_FORMAT_B10G10R10A2_SNORM:
|
||||||
|
return MALI_RGB10_A2_SNORM;
|
||||||
|
|
||||||
|
case PIPE_FORMAT_R10G10B10A2_UINT:
|
||||||
|
case PIPE_FORMAT_B10G10R10A2_UINT:
|
||||||
|
return MALI_RGB10_A2UI;
|
||||||
|
|
||||||
|
/* TODO: ZS isn't really special case */
|
||||||
|
case PIPE_FORMAT_Z32_UNORM:
|
||||||
|
return MALI_Z32_UNORM;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Fallthrough to default */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Formats must match in channel count */
|
||||||
|
assert(desc->nr_channels >= 1 && desc->nr_channels <= 4);
|
||||||
|
unsigned format = MALI_NR_CHANNELS(desc->nr_channels);
|
||||||
|
|
||||||
|
switch (chan.type) {
|
||||||
|
case UTIL_FORMAT_TYPE_UNSIGNED:
|
||||||
|
case UTIL_FORMAT_TYPE_SIGNED:
|
||||||
|
case UTIL_FORMAT_TYPE_FIXED:
|
||||||
|
/* Channel width */
|
||||||
|
format |= panfrost_translate_channel_width(chan.size);
|
||||||
|
|
||||||
|
/* Channel type */
|
||||||
|
format |= panfrost_translate_channel_type(chan.type, chan.size, chan.normalized);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UTIL_FORMAT_TYPE_FLOAT:
|
||||||
|
/* Float formats use a special width and encode width
|
||||||
|
* with type mixed */
|
||||||
|
|
||||||
|
format |= MALI_CHANNEL_FLOAT;
|
||||||
|
format |= panfrost_translate_channel_type(chan.type, chan.size, chan.normalized);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown format type in %s\n", desc->name);
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (enum mali_format) format;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
42
src/gallium/drivers/panfrost/pan_format.h
Normal file
42
src/gallium/drivers/panfrost/pan_format.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PAN_FORMAT_H__
|
||||||
|
#define __PAN_FORMAT_H__
|
||||||
|
|
||||||
|
#include "pan_context.h"
|
||||||
|
#include "util/u_format.h"
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
panfrost_translate_swizzle_4(const unsigned char swizzle[4]);
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
panfrost_get_default_swizzle(unsigned components);
|
||||||
|
|
||||||
|
enum mali_format
|
||||||
|
panfrost_find_format(const struct util_format_description *desc);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
224
src/gallium/drivers/panfrost/pan_pretty_print.c
Normal file
224
src/gallium/drivers/panfrost/pan_pretty_print.c
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2017-2098 The Panfrost Communiy
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pan_pretty_print.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* Some self-contained prettyprinting functions shared between panwrap and
|
||||||
|
* the main driver */
|
||||||
|
|
||||||
|
#define DEFINE_CASE(name) case MALI_## name: return "MALI_" #name
|
||||||
|
char *panwrap_format_name(enum mali_format format)
|
||||||
|
{
|
||||||
|
static char unk_format_str[5];
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
DEFINE_CASE(RGB10_A2_UNORM);
|
||||||
|
DEFINE_CASE(RGB10_A2_SNORM);
|
||||||
|
DEFINE_CASE(RGB10_A2UI);
|
||||||
|
DEFINE_CASE(RGB10_A2I);
|
||||||
|
DEFINE_CASE(NV12);
|
||||||
|
DEFINE_CASE(Z32_UNORM);
|
||||||
|
DEFINE_CASE(R32_FIXED);
|
||||||
|
DEFINE_CASE(RG32_FIXED);
|
||||||
|
DEFINE_CASE(RGB32_FIXED);
|
||||||
|
DEFINE_CASE(RGBA32_FIXED);
|
||||||
|
DEFINE_CASE(R11F_G11F_B10F);
|
||||||
|
DEFINE_CASE(VARYING_POS);
|
||||||
|
DEFINE_CASE(VARYING_DISCARD);
|
||||||
|
|
||||||
|
DEFINE_CASE(R8_SNORM);
|
||||||
|
DEFINE_CASE(R16_SNORM);
|
||||||
|
DEFINE_CASE(R32_SNORM);
|
||||||
|
DEFINE_CASE(RG8_SNORM);
|
||||||
|
DEFINE_CASE(RG16_SNORM);
|
||||||
|
DEFINE_CASE(RG32_SNORM);
|
||||||
|
DEFINE_CASE(RGB8_SNORM);
|
||||||
|
DEFINE_CASE(RGB16_SNORM);
|
||||||
|
DEFINE_CASE(RGB32_SNORM);
|
||||||
|
DEFINE_CASE(RGBA8_SNORM);
|
||||||
|
DEFINE_CASE(RGBA16_SNORM);
|
||||||
|
DEFINE_CASE(RGBA32_SNORM);
|
||||||
|
|
||||||
|
DEFINE_CASE(R8UI);
|
||||||
|
DEFINE_CASE(R16UI);
|
||||||
|
DEFINE_CASE(R32UI);
|
||||||
|
DEFINE_CASE(RG8UI);
|
||||||
|
DEFINE_CASE(RG16UI);
|
||||||
|
DEFINE_CASE(RG32UI);
|
||||||
|
DEFINE_CASE(RGB8UI);
|
||||||
|
DEFINE_CASE(RGB16UI);
|
||||||
|
DEFINE_CASE(RGB32UI);
|
||||||
|
DEFINE_CASE(RGBA8UI);
|
||||||
|
DEFINE_CASE(RGBA16UI);
|
||||||
|
DEFINE_CASE(RGBA32UI);
|
||||||
|
|
||||||
|
DEFINE_CASE(R8_UNORM);
|
||||||
|
DEFINE_CASE(R16_UNORM);
|
||||||
|
DEFINE_CASE(R32_UNORM);
|
||||||
|
DEFINE_CASE(R32F);
|
||||||
|
DEFINE_CASE(RG8_UNORM);
|
||||||
|
DEFINE_CASE(RG16_UNORM);
|
||||||
|
DEFINE_CASE(RG32_UNORM);
|
||||||
|
DEFINE_CASE(RG32F);
|
||||||
|
DEFINE_CASE(RGB8_UNORM);
|
||||||
|
DEFINE_CASE(RGB16_UNORM);
|
||||||
|
DEFINE_CASE(RGB32_UNORM);
|
||||||
|
DEFINE_CASE(RGB32F);
|
||||||
|
DEFINE_CASE(RGBA8_UNORM);
|
||||||
|
DEFINE_CASE(RGBA16_UNORM);
|
||||||
|
DEFINE_CASE(RGBA32_UNORM);
|
||||||
|
DEFINE_CASE(RGBA32F);
|
||||||
|
|
||||||
|
DEFINE_CASE(R8I);
|
||||||
|
DEFINE_CASE(R16I);
|
||||||
|
DEFINE_CASE(R32I);
|
||||||
|
DEFINE_CASE(RG8I);
|
||||||
|
DEFINE_CASE(R16F);
|
||||||
|
DEFINE_CASE(RG16I);
|
||||||
|
DEFINE_CASE(RG32I);
|
||||||
|
DEFINE_CASE(RG16F);
|
||||||
|
DEFINE_CASE(RGB8I);
|
||||||
|
DEFINE_CASE(RGB16I);
|
||||||
|
DEFINE_CASE(RGB32I);
|
||||||
|
DEFINE_CASE(RGB16F);
|
||||||
|
DEFINE_CASE(RGBA8I);
|
||||||
|
DEFINE_CASE(RGBA16I);
|
||||||
|
DEFINE_CASE(RGBA32I);
|
||||||
|
DEFINE_CASE(RGBA16F);
|
||||||
|
|
||||||
|
DEFINE_CASE(RGBA4);
|
||||||
|
DEFINE_CASE(RGBA8_2);
|
||||||
|
DEFINE_CASE(RGB10_A2_2);
|
||||||
|
default:
|
||||||
|
snprintf(unk_format_str, sizeof(unk_format_str), "0x%02x", format);
|
||||||
|
return unk_format_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef DEFINE_CASE
|
||||||
|
|
||||||
|
/* Helper to dump fixed-function blend part for debugging */
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
panfrost_factor_name(enum mali_dominant_factor factor)
|
||||||
|
{
|
||||||
|
switch (factor) {
|
||||||
|
case MALI_DOMINANT_UNK0:
|
||||||
|
return "unk0";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_ZERO:
|
||||||
|
return "zero";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_SRC_COLOR:
|
||||||
|
return "source color";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_DST_COLOR:
|
||||||
|
return "dest color";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_UNK4:
|
||||||
|
return "unk4";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_SRC_ALPHA:
|
||||||
|
return "source alpha";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_DST_ALPHA:
|
||||||
|
return "dest alpha";
|
||||||
|
|
||||||
|
case MALI_DOMINANT_CONSTANT:
|
||||||
|
return "constant";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unreachable";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
panfrost_modifier_name(enum mali_blend_modifier mod)
|
||||||
|
{
|
||||||
|
switch (mod) {
|
||||||
|
case MALI_BLEND_MOD_UNK0:
|
||||||
|
return "unk0";
|
||||||
|
|
||||||
|
case MALI_BLEND_MOD_NORMAL:
|
||||||
|
return "normal";
|
||||||
|
|
||||||
|
case MALI_BLEND_MOD_SOURCE_ONE:
|
||||||
|
return "source one";
|
||||||
|
|
||||||
|
case MALI_BLEND_MOD_DEST_ONE:
|
||||||
|
return "dest one";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unreachable";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_print_fixed_part(const char *name, unsigned u)
|
||||||
|
{
|
||||||
|
struct mali_blend_mode part;
|
||||||
|
memcpy(&part, &u, sizeof(part));
|
||||||
|
|
||||||
|
printf("%s blend mode (%X):\n", name, u);
|
||||||
|
|
||||||
|
printf(" %s dominant:\n",
|
||||||
|
(part.dominant == MALI_BLEND_DOM_SOURCE) ? "source" : "destination");
|
||||||
|
|
||||||
|
printf(" %s\n", panfrost_factor_name(part.dominant_factor));
|
||||||
|
|
||||||
|
if (part.complement_dominant)
|
||||||
|
printf(" complement\n");
|
||||||
|
|
||||||
|
|
||||||
|
printf(" nondominant %s\n",
|
||||||
|
(part.nondominant_mode == MALI_BLEND_NON_MIRROR) ? "mirror" : "zero");
|
||||||
|
|
||||||
|
|
||||||
|
printf(" mode: %s\n", panfrost_modifier_name(part.clip_modifier));
|
||||||
|
|
||||||
|
if (part.negate_source) printf(" negate source\n");
|
||||||
|
|
||||||
|
if (part.negate_dest) printf(" negate dest\n");
|
||||||
|
|
||||||
|
assert(!(part.unused_0 || part.unused_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_print_blend_equation(struct mali_blend_equation eq)
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
panfrost_print_fixed_part("RGB", eq.rgb_mode);
|
||||||
|
panfrost_print_fixed_part("Alpha", eq.alpha_mode);
|
||||||
|
|
||||||
|
assert(!eq.zero1);
|
||||||
|
|
||||||
|
printf("Mask: %s%s%s%s\n",
|
||||||
|
(eq.color_mask & MALI_MASK_R) ? "R" : "",
|
||||||
|
(eq.color_mask & MALI_MASK_G) ? "G" : "",
|
||||||
|
(eq.color_mask & MALI_MASK_B) ? "B" : "",
|
||||||
|
(eq.color_mask & MALI_MASK_A) ? "A" : "");
|
||||||
|
|
||||||
|
printf("Constant: %f\n", eq.constant);
|
||||||
|
}
|
||||||
32
src/gallium/drivers/panfrost/pan_pretty_print.h
Normal file
32
src/gallium/drivers/panfrost/pan_pretty_print.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2017-2098 The Panfrost Communiy
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PAN_PRETTY_H
|
||||||
|
#define __PAN_PRETTY_H
|
||||||
|
|
||||||
|
#include "panfrost-job.h"
|
||||||
|
|
||||||
|
char *panwrap_format_name(enum mali_format format);
|
||||||
|
void panfrost_print_blend_equation(struct mali_blend_equation eq);
|
||||||
|
|
||||||
|
#endif
|
||||||
432
src/gallium/drivers/panfrost/pan_resource.c
Normal file
432
src/gallium/drivers/panfrost/pan_resource.c
Normal file
|
|
@ -0,0 +1,432 @@
|
||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright 2008 VMware, Inc.
|
||||||
|
* Copyright 2014 Broadcom
|
||||||
|
* Copyright 2018 Alyssa Rosenzweig
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sub license, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the
|
||||||
|
* next paragraph) shall be included in all copies or substantial portions
|
||||||
|
* of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||||
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
|
||||||
|
#include "state_tracker/winsys_handle.h"
|
||||||
|
#include "util/u_format.h"
|
||||||
|
#include "util/u_memory.h"
|
||||||
|
#include "util/u_surface.h"
|
||||||
|
#include "util/u_transfer.h"
|
||||||
|
#include "util/u_transfer_helper.h"
|
||||||
|
|
||||||
|
#include "pan_context.h"
|
||||||
|
#include "pan_screen.h"
|
||||||
|
#include "pan_resource.h"
|
||||||
|
#include "pan_swizzle.h"
|
||||||
|
|
||||||
|
static struct pipe_resource *
|
||||||
|
panfrost_resource_from_handle(struct pipe_screen *pscreen,
|
||||||
|
const struct pipe_resource *templat,
|
||||||
|
struct winsys_handle *whandle,
|
||||||
|
unsigned usage)
|
||||||
|
{
|
||||||
|
struct panfrost_screen *screen = pan_screen(pscreen);
|
||||||
|
struct panfrost_resource *rsc;
|
||||||
|
struct pipe_resource *prsc;
|
||||||
|
|
||||||
|
assert(whandle->type == WINSYS_HANDLE_TYPE_FD);
|
||||||
|
|
||||||
|
rsc = CALLOC_STRUCT(panfrost_resource);
|
||||||
|
if (!rsc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
prsc = &rsc->base;
|
||||||
|
|
||||||
|
*prsc = *templat;
|
||||||
|
|
||||||
|
pipe_reference_init(&prsc->reference, 1);
|
||||||
|
prsc->screen = pscreen;
|
||||||
|
|
||||||
|
rsc->bo = screen->driver->import_bo(screen, whandle);
|
||||||
|
|
||||||
|
return prsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean
|
||||||
|
panfrost_resource_get_handle(struct pipe_screen *pscreen,
|
||||||
|
struct pipe_context *ctx,
|
||||||
|
struct pipe_resource *pt,
|
||||||
|
struct winsys_handle *handle,
|
||||||
|
unsigned usage)
|
||||||
|
{
|
||||||
|
struct panfrost_screen *screen = pan_screen(pscreen);
|
||||||
|
struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
|
||||||
|
struct renderonly_scanout *scanout = rsrc->scanout;
|
||||||
|
int bytes_per_pixel = util_format_get_blocksize(rsrc->base.format);
|
||||||
|
int stride = bytes_per_pixel * rsrc->base.width0; /* TODO: Alignment? */
|
||||||
|
|
||||||
|
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 (scanout) {
|
||||||
|
struct drm_prime_handle args = {
|
||||||
|
.handle = scanout->handle,
|
||||||
|
.flags = DRM_CLOEXEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = drmIoctl(screen->ro->kms_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
|
||||||
|
if (ret == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
handle->handle = args.fd;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
printf("Missed nonscanout FD handle\n");
|
||||||
|
assert(0);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "TODO %s\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_blit(struct pipe_context *pipe,
|
||||||
|
const struct pipe_blit_info *info)
|
||||||
|
{
|
||||||
|
/* STUB */
|
||||||
|
printf("Skipping blit XXX\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pipe_surface *
|
||||||
|
panfrost_create_surface(struct pipe_context *pipe,
|
||||||
|
struct pipe_resource *pt,
|
||||||
|
const struct pipe_surface *surf_tmpl)
|
||||||
|
{
|
||||||
|
struct pipe_surface *ps = NULL;
|
||||||
|
|
||||||
|
ps = CALLOC_STRUCT(pipe_surface);
|
||||||
|
|
||||||
|
if (ps) {
|
||||||
|
pipe_reference_init(&ps->reference, 1);
|
||||||
|
pipe_resource_reference(&ps->texture, pt);
|
||||||
|
ps->context = pipe;
|
||||||
|
ps->format = surf_tmpl->format;
|
||||||
|
|
||||||
|
if (pt->target != PIPE_BUFFER) {
|
||||||
|
assert(surf_tmpl->u.tex.level <= pt->last_level);
|
||||||
|
ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
|
||||||
|
ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
|
||||||
|
ps->u.tex.level = surf_tmpl->u.tex.level;
|
||||||
|
ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
|
||||||
|
ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
|
||||||
|
} else {
|
||||||
|
/* setting width as number of elements should get us correct renderbuffer width */
|
||||||
|
ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1;
|
||||||
|
ps->height = pt->height0;
|
||||||
|
ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
|
||||||
|
ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
|
||||||
|
assert(ps->u.buf.first_element <= ps->u.buf.last_element);
|
||||||
|
assert(ps->u.buf.last_element < ps->width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_surface_destroy(struct pipe_context *pipe,
|
||||||
|
struct pipe_surface *surf)
|
||||||
|
{
|
||||||
|
assert(surf->texture);
|
||||||
|
pipe_resource_reference(&surf->texture, NULL);
|
||||||
|
free(surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Proper resource tracking depends on, well, proper resources. This
|
||||||
|
* section will be woefully incomplete until we can sort out a proper DRM
|
||||||
|
* driver. */
|
||||||
|
|
||||||
|
static struct pipe_resource *
|
||||||
|
panfrost_resource_create(struct pipe_screen *screen,
|
||||||
|
const struct pipe_resource *template)
|
||||||
|
{
|
||||||
|
struct panfrost_resource *so = CALLOC_STRUCT(panfrost_resource);
|
||||||
|
struct panfrost_screen *pscreen = (struct panfrost_screen *) screen;
|
||||||
|
|
||||||
|
so->base = *template;
|
||||||
|
so->base.screen = screen;
|
||||||
|
|
||||||
|
pipe_reference_init(&so->base.reference, 1);
|
||||||
|
|
||||||
|
/* Make sure we're familiar */
|
||||||
|
switch (template->target) {
|
||||||
|
case PIPE_BUFFER:
|
||||||
|
case PIPE_TEXTURE_1D:
|
||||||
|
case PIPE_TEXTURE_2D:
|
||||||
|
case PIPE_TEXTURE_3D:
|
||||||
|
case PIPE_TEXTURE_RECT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "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 = pscreen->driver->create_bo(pscreen, template);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
so->bo = pscreen->driver->create_bo(pscreen, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Created resource %p with scanout %p\n", so, so->scanout);
|
||||||
|
|
||||||
|
return (struct pipe_resource *)so;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_resource_destroy(struct pipe_screen *screen,
|
||||||
|
struct pipe_resource *pt)
|
||||||
|
{
|
||||||
|
struct panfrost_screen *pscreen = panfrost_screen(screen);
|
||||||
|
struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
|
||||||
|
|
||||||
|
if (rsrc->scanout)
|
||||||
|
renderonly_scanout_destroy(rsrc->scanout, pscreen->ro);
|
||||||
|
|
||||||
|
if (rsrc->bo)
|
||||||
|
pscreen->driver->destroy_bo(pscreen, rsrc->bo);
|
||||||
|
|
||||||
|
FREE(rsrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
panfrost_transfer_map(struct pipe_context *pctx,
|
||||||
|
struct pipe_resource *resource,
|
||||||
|
unsigned level,
|
||||||
|
unsigned usage, /* a combination of PIPE_TRANSFER_x */
|
||||||
|
const struct pipe_box *box,
|
||||||
|
struct pipe_transfer **out_transfer)
|
||||||
|
{
|
||||||
|
struct panfrost_context *ctx = pan_context(pctx);
|
||||||
|
struct panfrost_screen *screen = panfrost_screen(pctx->screen);
|
||||||
|
int bytes_per_pixel = util_format_get_blocksize(resource->format);
|
||||||
|
int stride = bytes_per_pixel * resource->width0; /* TODO: Alignment? */
|
||||||
|
uint8_t *cpu;
|
||||||
|
|
||||||
|
struct pipe_transfer *transfer = CALLOC_STRUCT(pipe_transfer);
|
||||||
|
transfer->level = level;
|
||||||
|
transfer->usage = usage;
|
||||||
|
transfer->box = *box;
|
||||||
|
transfer->stride = stride;
|
||||||
|
assert(!transfer->box.z);
|
||||||
|
|
||||||
|
pipe_resource_reference(&transfer->resource, resource);
|
||||||
|
|
||||||
|
*out_transfer = transfer;
|
||||||
|
|
||||||
|
if (resource->bind & PIPE_BIND_DISPLAY_TARGET ||
|
||||||
|
resource->bind & PIPE_BIND_SCANOUT ||
|
||||||
|
resource->bind & PIPE_BIND_SHARED) {
|
||||||
|
/* Mipmapped readpixels?! */
|
||||||
|
assert(level == 0);
|
||||||
|
|
||||||
|
/* Force a flush -- kill the pipeline */
|
||||||
|
panfrost_flush(pctx, NULL, PIPE_FLUSH_END_OF_FRAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu = screen->driver->map_bo(ctx, transfer);
|
||||||
|
if (cpu == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return cpu + transfer->box.x * bytes_per_pixel + transfer->box.y * stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_transfer_unmap(struct pipe_context *pctx,
|
||||||
|
struct pipe_transfer *transfer)
|
||||||
|
{
|
||||||
|
struct panfrost_context *ctx = pan_context(pctx);
|
||||||
|
struct panfrost_screen *screen = pan_screen(pctx->screen);
|
||||||
|
|
||||||
|
screen->driver->unmap_bo(ctx, transfer);
|
||||||
|
|
||||||
|
/* Derefence the resource */
|
||||||
|
pipe_resource_reference(&transfer->resource, NULL);
|
||||||
|
|
||||||
|
/* Transfer itself is CALLOCed at the moment */
|
||||||
|
free(transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct pb_slab *
|
||||||
|
panfrost_slab_alloc(void *priv, unsigned heap, unsigned entry_size, unsigned group_index)
|
||||||
|
{
|
||||||
|
struct panfrost_screen *screen = (struct panfrost_screen *) priv;
|
||||||
|
struct panfrost_memory *mem = CALLOC_STRUCT(panfrost_memory);
|
||||||
|
|
||||||
|
size_t slab_size = (1 << (MAX_SLAB_ENTRY_SIZE + 1));
|
||||||
|
|
||||||
|
mem->slab.num_entries = slab_size / entry_size;
|
||||||
|
mem->slab.num_free = mem->slab.num_entries;
|
||||||
|
|
||||||
|
LIST_INITHEAD(&mem->slab.free);
|
||||||
|
for (unsigned i = 0; i < mem->slab.num_entries; ++i) {
|
||||||
|
/* Create a slab entry */
|
||||||
|
struct panfrost_memory_entry *entry = CALLOC_STRUCT(panfrost_memory_entry);
|
||||||
|
entry->offset = entry_size * i;
|
||||||
|
|
||||||
|
entry->base.slab = &mem->slab;
|
||||||
|
entry->base.group_index = group_index;
|
||||||
|
|
||||||
|
LIST_ADDTAIL(&entry->base.head, &mem->slab.free);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actually allocate the memory from kernel-space. Mapped, same_va, no
|
||||||
|
* special flags */
|
||||||
|
|
||||||
|
screen->driver->allocate_slab(screen, mem, slab_size / 4096, true, 0, 0, 0);
|
||||||
|
|
||||||
|
return &mem->slab;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
panfrost_slab_can_reclaim(void *priv, struct pb_slab_entry *entry)
|
||||||
|
{
|
||||||
|
struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry;
|
||||||
|
return p_entry->freed;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "TODO %s\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct u_transfer_vtbl transfer_vtbl = {
|
||||||
|
.resource_create = panfrost_resource_create,
|
||||||
|
.resource_destroy = panfrost_resource_destroy,
|
||||||
|
.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,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_resource_screen_init(struct panfrost_screen *pscreen)
|
||||||
|
{
|
||||||
|
//pscreen->base.resource_create_with_modifiers =
|
||||||
|
// panfrost_resource_create_with_modifiers;
|
||||||
|
pscreen->base.resource_create = u_transfer_helper_resource_create;
|
||||||
|
pscreen->base.resource_destroy = u_transfer_helper_resource_destroy;
|
||||||
|
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, true);
|
||||||
|
|
||||||
|
pb_slabs_init(&pscreen->slabs,
|
||||||
|
MIN_SLAB_ENTRY_SIZE,
|
||||||
|
MAX_SLAB_ENTRY_SIZE,
|
||||||
|
|
||||||
|
3, /* Number of heaps */
|
||||||
|
|
||||||
|
pscreen,
|
||||||
|
|
||||||
|
panfrost_slab_can_reclaim,
|
||||||
|
panfrost_slab_alloc,
|
||||||
|
panfrost_slab_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_resource_context_init(struct pipe_context *pctx)
|
||||||
|
{
|
||||||
|
pctx->transfer_map = u_transfer_helper_transfer_map;
|
||||||
|
pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
|
||||||
|
pctx->transfer_unmap = u_transfer_helper_transfer_unmap;
|
||||||
|
pctx->buffer_subdata = u_default_buffer_subdata;
|
||||||
|
pctx->create_surface = panfrost_create_surface;
|
||||||
|
pctx->surface_destroy = panfrost_surface_destroy;
|
||||||
|
pctx->resource_copy_region = util_resource_copy_region;
|
||||||
|
pctx->blit = panfrost_blit;
|
||||||
|
//pctx->generate_mipmap = panfrost_generate_mipmap;
|
||||||
|
pctx->flush_resource = panfrost_flush_resource;
|
||||||
|
pctx->invalidate_resource = panfrost_invalidate_resource;
|
||||||
|
pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region;
|
||||||
|
pctx->buffer_subdata = u_default_buffer_subdata;
|
||||||
|
pctx->texture_subdata = u_default_texture_subdata;
|
||||||
|
}
|
||||||
|
|
@ -48,6 +48,9 @@
|
||||||
#include "pan_public.h"
|
#include "pan_public.h"
|
||||||
|
|
||||||
#include "pan_context.h"
|
#include "pan_context.h"
|
||||||
|
#include "midgard/midgard_compile.h"
|
||||||
|
|
||||||
|
#include "pan_drm.h"
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
panfrost_get_name(struct pipe_screen *screen)
|
panfrost_get_name(struct pipe_screen *screen)
|
||||||
|
|
@ -513,7 +516,7 @@ panfrost_screen_get_compiler_options(struct pipe_screen *pscreen,
|
||||||
enum pipe_shader_ir ir,
|
enum pipe_shader_ir ir,
|
||||||
enum pipe_shader_type shader)
|
enum pipe_shader_type shader)
|
||||||
{
|
{
|
||||||
return NULL;
|
return &midgard_nir_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pipe_screen *
|
struct pipe_screen *
|
||||||
|
|
@ -533,6 +536,18 @@ panfrost_create_screen(int fd, struct renderonly *ro, bool is_drm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_drm) {
|
||||||
|
screen->driver = panfrost_create_drm_driver(fd);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Legacy (non-DRM) drivers are not supported in upstream Mesa\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DUMP_PERFORMANCE_COUNTERS
|
||||||
|
screen->driver->allocate_slab(screen, &screen->perf_counters, 64, true, 0, 0, 0);
|
||||||
|
screen->driver->enable_counters(screen);
|
||||||
|
#endif
|
||||||
|
|
||||||
screen->base.destroy = panfrost_destroy_screen;
|
screen->base.destroy = panfrost_destroy_screen;
|
||||||
|
|
||||||
screen->base.get_name = panfrost_get_name;
|
screen->base.get_name = panfrost_get_name;
|
||||||
|
|
@ -543,7 +558,7 @@ panfrost_create_screen(int fd, struct renderonly *ro, bool is_drm)
|
||||||
screen->base.get_paramf = panfrost_get_paramf;
|
screen->base.get_paramf = panfrost_get_paramf;
|
||||||
screen->base.get_timestamp = panfrost_get_timestamp;
|
screen->base.get_timestamp = panfrost_get_timestamp;
|
||||||
screen->base.is_format_supported = panfrost_is_format_supported;
|
screen->base.is_format_supported = panfrost_is_format_supported;
|
||||||
//screen->base.context_create = panfrost_create_context;
|
screen->base.context_create = panfrost_create_context;
|
||||||
screen->base.flush_frontbuffer = panfrost_flush_frontbuffer;
|
screen->base.flush_frontbuffer = panfrost_flush_frontbuffer;
|
||||||
screen->base.get_compiler_options = panfrost_screen_get_compiler_options;
|
screen->base.get_compiler_options = panfrost_screen_get_compiler_options;
|
||||||
screen->base.fence_reference = panfrost_fence_reference;
|
screen->base.fence_reference = panfrost_fence_reference;
|
||||||
|
|
@ -552,6 +567,7 @@ panfrost_create_screen(int fd, struct renderonly *ro, bool is_drm)
|
||||||
screen->last_fragment_id = -1;
|
screen->last_fragment_id = -1;
|
||||||
screen->last_fragment_flushed = true;
|
screen->last_fragment_flushed = true;
|
||||||
|
|
||||||
fprintf(stderr, "stub: Upstream panfrost (use downstream fork)\n");
|
panfrost_resource_screen_init(screen);
|
||||||
return NULL;
|
|
||||||
|
return &screen->base;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,10 @@ struct panfrost_screen;
|
||||||
|
|
||||||
//#define DUMP_PERFORMANCE_COUNTERS
|
//#define DUMP_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
/* Flags for allocated memory */
|
||||||
|
#define PAN_ALLOCATE_EXECUTE (1 << 0)
|
||||||
|
#define PAN_ALLOCATE_GROWABLE (1 << 1)
|
||||||
|
|
||||||
struct panfrost_driver {
|
struct panfrost_driver {
|
||||||
struct panfrost_bo * (*create_bo) (struct panfrost_screen *screen, const struct pipe_resource *template);
|
struct panfrost_bo * (*create_bo) (struct panfrost_screen *screen, const struct pipe_resource *template);
|
||||||
struct panfrost_bo * (*import_bo) (struct panfrost_screen *screen, struct winsys_handle *whandle);
|
struct panfrost_bo * (*import_bo) (struct panfrost_screen *screen, struct winsys_handle *whandle);
|
||||||
|
|
@ -49,7 +53,7 @@ struct panfrost_driver {
|
||||||
void (*unmap_bo) (struct panfrost_context *ctx, struct pipe_transfer *transfer);
|
void (*unmap_bo) (struct panfrost_context *ctx, struct pipe_transfer *transfer);
|
||||||
void (*destroy_bo) (struct panfrost_screen *screen, struct panfrost_bo *bo);
|
void (*destroy_bo) (struct panfrost_screen *screen, struct panfrost_bo *bo);
|
||||||
|
|
||||||
void (*submit_job) (struct panfrost_context *ctx, mali_ptr addr, int nr_atoms);
|
int (*submit_vs_fs_job) (struct panfrost_context *ctx, bool has_draws);
|
||||||
void (*force_flush_fragment) (struct panfrost_context *ctx);
|
void (*force_flush_fragment) (struct panfrost_context *ctx);
|
||||||
void (*allocate_slab) (struct panfrost_screen *screen,
|
void (*allocate_slab) (struct panfrost_screen *screen,
|
||||||
struct panfrost_memory *mem,
|
struct panfrost_memory *mem,
|
||||||
|
|
|
||||||
234
src/gallium/drivers/panfrost/pan_swizzle.c
Normal file
234
src/gallium/drivers/panfrost/pan_swizzle.c
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2013 Luc Verhaegen <libv@skynet.be>
|
||||||
|
* Copyright (c) 2018 Alyssa Rosenzweig <alyssa@rosenzweig.io>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the
|
||||||
|
* next paragraph) shall be included in all copies or substantial portions
|
||||||
|
* of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "pan_swizzle.h"
|
||||||
|
#include "pan_allocate.h"
|
||||||
|
|
||||||
|
/* Space a group of 4-bits out. For instance, 0x7 -- that is, 0b111 -- would
|
||||||
|
* become 0b10101 */
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
space_bits_4(int i)
|
||||||
|
{
|
||||||
|
return ((i & 0x8) << 3) |
|
||||||
|
((i & 0x4) << 2) |
|
||||||
|
((i & 0x2) << 1) |
|
||||||
|
((i & 0x1) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate lookup table for the space filler curve. Note this is a 1:1
|
||||||
|
* mapping, just with bits twiddled around. */
|
||||||
|
|
||||||
|
uint32_t space_filler[16][16];
|
||||||
|
uint32_t space_filler_packed4[16][4];
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_generate_space_filler_indices()
|
||||||
|
{
|
||||||
|
for (int y = 0; y < 16; ++y) {
|
||||||
|
for (int x = 0; x < 16; ++x) {
|
||||||
|
space_filler[y][x] =
|
||||||
|
space_bits_4(y ^ x) | (space_bits_4(y) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int q = 0; q < 4; ++q) {
|
||||||
|
space_filler_packed4[y][q] =
|
||||||
|
(space_filler[y][(q * 4) + 0] << 0) |
|
||||||
|
(space_filler[y][(q * 4) + 1] << 8) |
|
||||||
|
(space_filler[y][(q * 4) + 2] << 16) |
|
||||||
|
(space_filler[y][(q * 4) + 3] << 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swizzle_bpp1_align16(int width, int height, int source_stride, int block_pitch,
|
||||||
|
const uint8_t *pixels,
|
||||||
|
uint8_t *ldest)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
{
|
||||||
|
int block_y = y & ~(0x0f);
|
||||||
|
int rem_y = y & 0x0f;
|
||||||
|
uint8_t *block_start_s = ldest + (block_y * block_pitch);
|
||||||
|
const uint8_t *source_start = pixels + (y * source_stride);
|
||||||
|
const uint8_t *source_end = source_start + width;
|
||||||
|
|
||||||
|
/* Operate on blocks of 16 pixels to minimise bookkeeping */
|
||||||
|
|
||||||
|
for (; source_start < source_end; block_start_s += 16 * 16, source_start += 16) {
|
||||||
|
const uint32_t *src_32 = (const uint32_t *) source_start;
|
||||||
|
|
||||||
|
for (int q = 0; q < 4; ++q) {
|
||||||
|
uint32_t src = src_32[q];
|
||||||
|
uint32_t spaced = space_filler_packed4[rem_y][q];
|
||||||
|
uint16_t *bs = (uint16_t *) block_start_s;
|
||||||
|
|
||||||
|
int spacedA = (spaced >> 0) & 0xFF;
|
||||||
|
int spacedB = (spaced >> 16) & 0xFF;
|
||||||
|
|
||||||
|
bs[spacedA >> 1] = (src >> 0) & 0xFFFF;
|
||||||
|
bs[spacedB >> 1] = (src >> 16) & 0xFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++y;
|
||||||
|
|
||||||
|
{
|
||||||
|
int block_y = y & ~(0x0f);
|
||||||
|
int rem_y = y & 0x0f;
|
||||||
|
uint8_t *block_start_s = ldest + (block_y * block_pitch);
|
||||||
|
const uint8_t *source_start = pixels + (y * source_stride);
|
||||||
|
const uint8_t *source_end = source_start + width;
|
||||||
|
|
||||||
|
/* Operate on blocks of 16 pixels to minimise bookkeeping */
|
||||||
|
|
||||||
|
for (; source_start < source_end; block_start_s += 16 * 16, source_start += 16) {
|
||||||
|
const uint32_t *src_32 = (const uint32_t *) source_start;
|
||||||
|
|
||||||
|
for (int q = 0; q < 4; ++q) {
|
||||||
|
uint32_t src = src_32[q];
|
||||||
|
uint32_t spaced = space_filler_packed4[rem_y][q];
|
||||||
|
|
||||||
|
block_start_s[(spaced >> 0) & 0xFF] = (src >> 0) & 0xFF;
|
||||||
|
block_start_s[(spaced >> 8) & 0xFF] = (src >> 8) & 0xFF;
|
||||||
|
|
||||||
|
block_start_s[(spaced >> 16) & 0xFF] = (src >> 16) & 0xFF;
|
||||||
|
block_start_s[(spaced >> 24) & 0xFF] = (src >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swizzle_bpp4_align16(int width, int height, int source_stride, int block_pitch,
|
||||||
|
const uint32_t *pixels,
|
||||||
|
uint32_t *ldest)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
int block_y = y & ~(0x0f);
|
||||||
|
int rem_y = y & 0x0f;
|
||||||
|
uint32_t *block_start_s = ldest + (block_y * block_pitch);
|
||||||
|
const uint32_t *source_start = pixels + (y * source_stride);
|
||||||
|
const uint32_t *source_end = source_start + width;
|
||||||
|
|
||||||
|
/* Operate on blocks of 16 pixels to minimise bookkeeping */
|
||||||
|
|
||||||
|
for (; source_start < source_end; block_start_s += 16 * 16, source_start += 16) {
|
||||||
|
for (int j = 0; j < 16; ++j)
|
||||||
|
block_start_s[space_filler[rem_y][j]] = source_start[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_texture_swizzle(int width, int height, int bytes_per_pixel, int source_stride,
|
||||||
|
const uint8_t *pixels,
|
||||||
|
uint8_t *ldest)
|
||||||
|
{
|
||||||
|
/* Calculate maximum size, overestimating a bit */
|
||||||
|
int block_pitch = ALIGN(width, 16) >> 4;
|
||||||
|
|
||||||
|
/* Use fast path if available */
|
||||||
|
if (bytes_per_pixel == 4 /* && (ALIGN(width, 16) == width) */) {
|
||||||
|
swizzle_bpp4_align16(width, height, source_stride >> 2, (block_pitch * 256 >> 4), (const uint32_t *) pixels, (uint32_t *) ldest);
|
||||||
|
return;
|
||||||
|
} else if (bytes_per_pixel == 1 /* && (ALIGN(width, 16) == width) */) {
|
||||||
|
swizzle_bpp1_align16(width, height, source_stride, (block_pitch * 256 >> 4), pixels, (uint8_t *) ldest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, default back on generic path */
|
||||||
|
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
int block_y = y >> 4;
|
||||||
|
int rem_y = y & 0x0F;
|
||||||
|
int block_start_s = block_y * block_pitch * 256;
|
||||||
|
int source_start = y * source_stride;
|
||||||
|
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
int block_x_s = (x >> 4) * 256;
|
||||||
|
int rem_x = x & 0x0F;
|
||||||
|
|
||||||
|
int index = space_filler[rem_y][rem_x];
|
||||||
|
const uint8_t *source = &pixels[source_start + bytes_per_pixel * x];
|
||||||
|
uint8_t *dest = ldest + bytes_per_pixel * (block_start_s + block_x_s + index);
|
||||||
|
|
||||||
|
for (int b = 0; b < bytes_per_pixel; ++b)
|
||||||
|
dest[b] = source[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
panfrost_swizzled_size(int width, int height, int bytes_per_pixel)
|
||||||
|
{
|
||||||
|
/* Calculate maximum size, overestimating a bit */
|
||||||
|
int block_pitch = ALIGN(width, 16) >> 4;
|
||||||
|
unsigned sz = bytes_per_pixel * 256 * ((height >> 4) + 1) * block_pitch;
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#define TW 1920
|
||||||
|
#define TH 1080
|
||||||
|
void
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
panfrost_generate_space_filler_indices();
|
||||||
|
|
||||||
|
uint8_t in[TW * TH * 4];
|
||||||
|
|
||||||
|
for (int i = 0; i < TW * TH * 4; ++i) in[i] = i;
|
||||||
|
|
||||||
|
uint8_t *out = malloc(TW * TH * 4 * 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 60; ++i) {
|
||||||
|
//swizzle_bpp4_align16(TW, TH, TW*4, TW>>4, (uint32_t *) in, (uint32_t *) out);
|
||||||
|
//panfrost_texture_swizzle_bpp4(TW, TH, TW*4, (uint32_t *) in, (uint32_t *) out);
|
||||||
|
//panfrost_texture_swizzle(TW, TH, 4, TW*4, (uint32_t *) in, (uint32_t *) out);
|
||||||
|
|
||||||
|
int block_pitch = ALIGN(TW, 16) >> 4;
|
||||||
|
swizzle_bpp1_align16(TW, TH, TW, (block_pitch * 256 >> 4), in, (uint8_t *) out);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
uint8_t *reference = malloc(TW * TH * 4 * 2);
|
||||||
|
panfrost_texture_swizzle(TW, TH, 1, TW, (uint8_t *) in, (uint8_t *) reference);
|
||||||
|
|
||||||
|
if (memcmp(reference, out, TW * TH * 4)) printf("XXX\n");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
printf("ref %X\n", out[0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
41
src/gallium/drivers/panfrost/pan_swizzle.h
Normal file
41
src/gallium/drivers/panfrost/pan_swizzle.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TEXSWZ_H__
|
||||||
|
#define __TEXSWZ_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_generate_space_filler_indices(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_texture_swizzle(int width, int height, int bytes_per_pixel, int source_stride,
|
||||||
|
const uint8_t *pixels,
|
||||||
|
uint8_t *ldest);
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
panfrost_swizzled_size(int width, int height, int bytes_per_pixel);
|
||||||
|
|
||||||
|
#endif
|
||||||
275
src/gallium/drivers/panfrost/pan_wallpaper.c
Normal file
275
src/gallium/drivers/panfrost/pan_wallpaper.c
Normal file
|
|
@ -0,0 +1,275 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pan_wallpaper.h"
|
||||||
|
#include "pan_context.h"
|
||||||
|
#include "pan_screen.h"
|
||||||
|
//#include "include/panfrost-job.h"
|
||||||
|
#include "midgard/midgard_compile.h"
|
||||||
|
#include "compiler/nir/nir_builder.h"
|
||||||
|
|
||||||
|
/* Creates the special-purpose fragment shader for wallpapering. A
|
||||||
|
* pseudo-vertex shader sets us up for a fullscreen quad render, with a texture
|
||||||
|
* coordinate varying */
|
||||||
|
|
||||||
|
static nir_shader *
|
||||||
|
panfrost_build_wallpaper_program()
|
||||||
|
{
|
||||||
|
nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
|
||||||
|
nir_function *fn = nir_function_create(shader, "main");
|
||||||
|
nir_function_impl *impl = nir_function_impl_create(fn);
|
||||||
|
|
||||||
|
/* Create the variables variables */
|
||||||
|
|
||||||
|
nir_variable *c_texcoord = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_TexCoord");
|
||||||
|
nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_FragColor");
|
||||||
|
|
||||||
|
c_texcoord->data.location = VARYING_SLOT_VAR0;
|
||||||
|
c_out->data.location = FRAG_RESULT_COLOR;
|
||||||
|
|
||||||
|
/* Setup nir_builder */
|
||||||
|
|
||||||
|
nir_builder _b;
|
||||||
|
nir_builder *b = &_b;
|
||||||
|
nir_builder_init(b, impl);
|
||||||
|
b->cursor = nir_before_block(nir_start_block(impl));
|
||||||
|
|
||||||
|
/* Setup inputs */
|
||||||
|
|
||||||
|
nir_ssa_def *s_src = nir_load_var(b, c_texcoord);
|
||||||
|
|
||||||
|
/* Build the passthrough texture shader */
|
||||||
|
|
||||||
|
nir_tex_instr *tx = nir_tex_instr_create(shader, 1);
|
||||||
|
tx->op = nir_texop_tex;
|
||||||
|
tx->texture_index = tx->sampler_index = 0;
|
||||||
|
tx->sampler_dim = GLSL_SAMPLER_DIM_2D;
|
||||||
|
tx->dest_type = nir_type_float;
|
||||||
|
|
||||||
|
nir_src src = nir_src_for_ssa(s_src);
|
||||||
|
nir_src_copy(&tx->src[0].src, &src, tx);
|
||||||
|
tx->src[0].src_type = nir_tex_src_coord;
|
||||||
|
|
||||||
|
nir_ssa_dest_init(&tx->instr, &tx->dest, nir_tex_instr_dest_size(tx), 32, NULL);
|
||||||
|
nir_builder_instr_insert(b, &tx->instr);
|
||||||
|
|
||||||
|
nir_ssa_def *texel = &tx->dest.ssa;
|
||||||
|
|
||||||
|
nir_store_var(b, c_out, texel, 0xFF);
|
||||||
|
|
||||||
|
nir_print_shader(shader, stdout);
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates the CSO corresponding to the wallpaper program */
|
||||||
|
|
||||||
|
static struct panfrost_shader_variants *
|
||||||
|
panfrost_create_wallpaper_program(struct pipe_context *pctx)
|
||||||
|
{
|
||||||
|
nir_shader *built_nir_shader = panfrost_build_wallpaper_program();
|
||||||
|
|
||||||
|
struct pipe_shader_state so = {
|
||||||
|
.type = PIPE_SHADER_IR_NIR,
|
||||||
|
.ir = {
|
||||||
|
.nir = built_nir_shader
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return pctx->create_fs_state(pctx, &so);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct panfrost_shader_variants *wallpaper_program = NULL;
|
||||||
|
static struct panfrost_shader_variants *wallpaper_saved_program = NULL;
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_enable_wallpaper_program(struct pipe_context *pctx)
|
||||||
|
{
|
||||||
|
struct panfrost_context *ctx = pan_context(pctx);
|
||||||
|
|
||||||
|
if (!wallpaper_program) {
|
||||||
|
wallpaper_program = panfrost_create_wallpaper_program(pctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push the shader state */
|
||||||
|
wallpaper_saved_program = ctx->fs;
|
||||||
|
|
||||||
|
/* Bind the program */
|
||||||
|
pctx->bind_fs_state(pctx, wallpaper_program);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
panfrost_disable_wallpaper_program(struct pipe_context *pctx)
|
||||||
|
{
|
||||||
|
/* Pop off the shader state */
|
||||||
|
pctx->bind_fs_state(pctx, wallpaper_saved_program);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Essentially, we insert a fullscreen textured quad, reading from the
|
||||||
|
* previous frame's framebuffer */
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_draw_wallpaper(struct pipe_context *pipe)
|
||||||
|
{
|
||||||
|
/* Disable wallpapering for now, but still exercise the shader generation to minimise bit rot */
|
||||||
|
|
||||||
|
panfrost_enable_wallpaper_program(pipe);
|
||||||
|
panfrost_disable_wallpaper_program(pipe);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
struct panfrost_context *ctx = pan_context(pipe);
|
||||||
|
|
||||||
|
/* Setup payload for elided quad. TODO: Refactor draw_vbo so this can
|
||||||
|
* be a little more DRY */
|
||||||
|
|
||||||
|
ctx->payload_tiler.draw_start = 0;
|
||||||
|
ctx->payload_tiler.prefix.draw_mode = MALI_TRIANGLE_STRIP;
|
||||||
|
ctx->vertex_count = 4;
|
||||||
|
ctx->payload_tiler.prefix.invocation_count = MALI_POSITIVE(4);
|
||||||
|
ctx->payload_tiler.prefix.unknown_draw &= ~(0x3000 | 0x18000);
|
||||||
|
ctx->payload_tiler.prefix.unknown_draw |= 0x18000;
|
||||||
|
ctx->payload_tiler.prefix.negative_start = 0;
|
||||||
|
ctx->payload_tiler.prefix.index_count = MALI_POSITIVE(4);
|
||||||
|
ctx->payload_tiler.prefix.unknown_draw &= ~MALI_DRAW_INDEXED_UINT32;
|
||||||
|
ctx->payload_tiler.prefix.indices = (uintptr_t) NULL;
|
||||||
|
|
||||||
|
/* Setup the wallpapering program. We need to build the program via
|
||||||
|
* NIR. */
|
||||||
|
|
||||||
|
panfrost_enable_wallpaper_program(pipe);
|
||||||
|
|
||||||
|
/* Setup the texture/sampler pair */
|
||||||
|
|
||||||
|
struct pipe_sampler_view tmpl = {
|
||||||
|
.target = PIPE_TEXTURE_2D,
|
||||||
|
.swizzle_r = PIPE_SWIZZLE_X,
|
||||||
|
.swizzle_g = PIPE_SWIZZLE_Y,
|
||||||
|
.swizzle_b = PIPE_SWIZZLE_Z,
|
||||||
|
.swizzle_a = PIPE_SWIZZLE_W
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pipe_sampler_state state = {
|
||||||
|
.min_mip_filter = PIPE_TEX_MIPFILTER_NONE,
|
||||||
|
.min_img_filter = PIPE_TEX_MIPFILTER_LINEAR,
|
||||||
|
.mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR,
|
||||||
|
.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
|
||||||
|
.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
|
||||||
|
.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
|
||||||
|
.normalized_coords = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pipe_resource *rsrc = panfrost_screen(pipe->screen)->display_target;
|
||||||
|
struct pipe_sampler_state *sampler_state = pipe->create_sampler_state(pipe, &state);
|
||||||
|
struct pipe_sampler_view *sampler_view = pipe->create_sampler_view(pipe, rsrc, &tmpl);
|
||||||
|
|
||||||
|
/* Bind texture/sampler. TODO: push/pop */
|
||||||
|
pipe->bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state);
|
||||||
|
pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_view);
|
||||||
|
|
||||||
|
panfrost_emit_for_draw(ctx, false);
|
||||||
|
|
||||||
|
/* Elision occurs by essential precomputing the results of the
|
||||||
|
* implied vertex shader. Insert these results for fullscreen. The
|
||||||
|
* first two channels are ~screenspace coordinates, whereas the latter
|
||||||
|
* two are fixed 0.0/1.0 after perspective division. See the vertex
|
||||||
|
* shader epilogue for more context */
|
||||||
|
|
||||||
|
float implied_position_varying[] = {
|
||||||
|
/* The following is correct for scissored clears whose scissor deals with cutoff appropriately */
|
||||||
|
|
||||||
|
// -1.0, -1.0, 0.0, 1.0,
|
||||||
|
// -1.0, 65535.0, 0.0, 1.0,
|
||||||
|
// 65536.0, 1.0, 0.0, 1.0,
|
||||||
|
// 65536.0, 65536.0, 0.0, 1.0
|
||||||
|
|
||||||
|
/* The following output is correct for a fullscreen quad with screen size 2048x1600 */
|
||||||
|
0.0, 0.0, 0.0, 1.0,
|
||||||
|
0.0, 1600.0, 0.0, 1.0,
|
||||||
|
2048.0, 0.0, 0.0, 1.0,
|
||||||
|
2048.0, 1280.0, 0.0, 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx->payload_tiler.postfix.position_varying = panfrost_upload_transient(ctx, implied_position_varying, sizeof(implied_position_varying));
|
||||||
|
|
||||||
|
/* Similarly, setup the texture coordinate varying, hardcoded to match
|
||||||
|
* the corners of the screen */
|
||||||
|
|
||||||
|
float texture_coordinates[] = {
|
||||||
|
0.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
1.0, 1.0, 0.0, 0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
union mali_attr varyings[1] = {
|
||||||
|
{
|
||||||
|
.elements = panfrost_upload_transient(ctx, texture_coordinates, sizeof(texture_coordinates)) | 1,
|
||||||
|
.stride = sizeof(float) * 4,
|
||||||
|
.size = sizeof(texture_coordinates)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx->payload_tiler.postfix.varyings = panfrost_upload_transient(ctx, varyings, sizeof(varyings));
|
||||||
|
|
||||||
|
struct mali_attr_meta varying_meta[1] = {
|
||||||
|
{
|
||||||
|
.type = MALI_ATYPE_FLOAT,
|
||||||
|
.nr_components = MALI_POSITIVE(4),
|
||||||
|
.not_normalised = 1,
|
||||||
|
.unknown1 = /*0x2c22 - nr_comp=2*/ 0x2a22,
|
||||||
|
.unknown2 = 0x1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mali_ptr saved_varying_meta = ctx->payload_tiler.postfix.varying_meta;
|
||||||
|
ctx->payload_tiler.postfix.varying_meta = panfrost_upload_transient(ctx, varying_meta, sizeof(varying_meta));
|
||||||
|
|
||||||
|
/* Emit the tiler job */
|
||||||
|
struct panfrost_transfer tiler = panfrost_vertex_tiler_job(ctx, true, true);
|
||||||
|
struct mali_job_descriptor_header *jd = (struct mali_job_descriptor_header *) tiler.cpu;
|
||||||
|
ctx->u_tiler_jobs[ctx->tiler_job_count] = jd;
|
||||||
|
ctx->tiler_jobs[ctx->tiler_job_count++] = tiler.gpu;
|
||||||
|
ctx->draw_count++;
|
||||||
|
|
||||||
|
/* Okay, so we have the tiler job emitted. Since we set elided_tiler
|
||||||
|
* mode, no dependencies will be set automatically. We don't actually
|
||||||
|
* want any dependencies, since we go first and we don't need a vertex
|
||||||
|
* first. That said, we do need the first tiler job to depend on us.
|
||||||
|
* Its second dep slot will be free (see the panfrost_vertex_tiler_job
|
||||||
|
* dependency setting algorithm), so fill us in with that
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ctx->tiler_job_count > 1) {
|
||||||
|
ctx->u_tiler_jobs[0]->job_dependency_index_2 = jd->job_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Wallpaper boop\n");
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
panfrost_disable_wallpaper_program(pipe);
|
||||||
|
ctx->payload_tiler.postfix.varying_meta = saved_varying_meta;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
33
src/gallium/drivers/panfrost/pan_wallpaper.h
Normal file
33
src/gallium/drivers/panfrost/pan_wallpaper.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* © Copyright 2018 Alyssa Rosenzweig
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PAN_WALLPAPER_H
|
||||||
|
#define __PAN_WALLPAPER_H
|
||||||
|
|
||||||
|
#include "pipe/p_state.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
panfrost_draw_wallpaper(struct pipe_context *pipe);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Reference in a new issue