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:
Alyssa Rosenzweig 2019-02-05 04:32:27 +00:00
parent 8f4485ef1a
commit 7da251fc72
22 changed files with 5441 additions and 5 deletions

View file

@ -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 = [

View 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;
}

View 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;
}
}

View 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);
}

View 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

View 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;
}

View 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

File diff suppressed because it is too large Load diff

View file

@ -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);

View 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;
}

View 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__ */

View 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;
}

View 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

View 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);
}

View 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

View 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;
}

View file

@ -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;
}

View file

@ -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,

View 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

View 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

View 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
}

View 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