mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-25 08:40:11 +01: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_screen.c',
|
||||
'pan_screen.h',
|
||||
'pan_resource.c',
|
||||
'pan_resource.h',
|
||||
|
||||
'midgard/midgard_compile.c',
|
||||
'midgard/cppwrap.cpp',
|
||||
'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 = [
|
||||
|
|
|
|||
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,
|
||||
unsigned flags);
|
||||
|
||||
mali_ptr
|
||||
panfrost_fragment_job(struct panfrost_context *ctx);
|
||||
|
||||
void
|
||||
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_context.h"
|
||||
#include "midgard/midgard_compile.h"
|
||||
|
||||
#include "pan_drm.h"
|
||||
|
||||
static const char *
|
||||
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_type shader)
|
||||
{
|
||||
return NULL;
|
||||
return &midgard_nir_options;
|
||||
}
|
||||
|
||||
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.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_timestamp = panfrost_get_timestamp;
|
||||
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.get_compiler_options = panfrost_screen_get_compiler_options;
|
||||
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_flushed = true;
|
||||
|
||||
fprintf(stderr, "stub: Upstream panfrost (use downstream fork)\n");
|
||||
return NULL;
|
||||
panfrost_resource_screen_init(screen);
|
||||
|
||||
return &screen->base;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ struct panfrost_screen;
|
|||
|
||||
//#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_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);
|
||||
|
|
@ -49,7 +53,7 @@ struct panfrost_driver {
|
|||
void (*unmap_bo) (struct panfrost_context *ctx, struct pipe_transfer *transfer);
|
||||
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 (*allocate_slab) (struct panfrost_screen *screen,
|
||||
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