pvr: Add support for sampler border colors
authorMatt Coster <matt.coster@imgtec.com>
Fri, 24 Feb 2023 14:06:39 +0000 (14:06 +0000)
committerMarge Bot <emma+marge@anholt.net>
Thu, 8 Jun 2023 10:33:46 +0000 (10:33 +0000)
Currently only the six vulkan 1.0 pre-defined formats are supported,
but some basic infrastructure that will be useful for implementing
VK_EXT_custom_border_color (and vulkan 1.1) is included.

Only formats currently listed in the pvr_format_table in pvr_formats.c
are currently supported. Unlike most (all?) other drivers, the PowerVR
hardware requires each entry in the border color table to be encoded
for every hardware format (of which there are 128 available, plus 128
for compressed formats).

Also in this commit:
 - Two new constants in rogue_texstate.xml:
    - IMAGE_WORD0_TEXFORMAT_MAX_SIZE, and
    - SAMPLER_BORDERCOLOR_INDEX_MAX_SIZE; and
 - A new device feature (tpu_border_colour_enhanced)

Signed-off-by: Matt Coster <matt.coster@imgtec.com>
Reviewed-by: Karmjit Mahil <Karmjit.Mahil@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21555>

12 files changed:
src/imagination/common/pvr_device_info.c
src/imagination/common/pvr_device_info.h
src/imagination/csbgen/rogue_texstate.xml
src/imagination/vulkan/meson.build
src/imagination/vulkan/pvr_border.c [new file with mode: 0644]
src/imagination/vulkan/pvr_border.h [new file with mode: 0644]
src/imagination/vulkan/pvr_cmd_buffer.c
src/imagination/vulkan/pvr_device.c
src/imagination/vulkan/pvr_job_compute.c
src/imagination/vulkan/pvr_job_render.c
src/imagination/vulkan/pvr_job_render.h
src/imagination/vulkan/pvr_private.h

index c1dd1db..85161bb 100644 (file)
@@ -151,6 +151,7 @@ const struct pvr_device_features pvr_device_features_33_V_11_3 = {
    .has_tile_size_16x16 = true,
    .has_tile_size_x = true,
    .has_tile_size_y = true,
+   .has_tpu_border_colour_enhanced = true,
    .has_tpu_extended_integer_lookup = true,
    .has_tpu_image_state_v2 = true,
    .has_usc_f16sop_u8 = true,
@@ -235,6 +236,7 @@ const struct pvr_device_features pvr_device_features_36_V_104_796 = {
    .has_tile_size_16x16 = true,
    .has_tile_size_x = true,
    .has_tile_size_y = true,
+   .has_tpu_border_colour_enhanced = true,
    .has_tpu_extended_integer_lookup = true,
    .has_tpu_image_state_v2 = true,
    .has_usc_f16sop_u8 = true,
index ed8286d..8fdb26d 100644 (file)
@@ -286,6 +286,7 @@ struct pvr_device_features {
    bool has_tile_size_x : 1;
    bool has_tile_size_y : 1;
    bool has_tpu_array_textures : 1;
+   bool has_tpu_border_colour_enhanced : 1;
    bool has_tpu_extended_integer_lookup : 1;
    bool has_tpu_image_state_v2 : 1;
    bool has_usc_f16sop_u8 : 1;
index 79c91eb..dd18155 100644 (file)
@@ -267,7 +267,9 @@ SOFTWARE.
     <field name="width" start="34" end="47" type="uint">
       <define name="MAX_SIZE" value="16383"/>
     </field>
-    <field name="texformat" start="27" end="33" type="FORMAT"/>
+    <field name="texformat" start="27" end="33" type="FORMAT">
+      <define name="MAX_SIZE" value="127"/>
+    </field>
     <field name="texformat_compressed" start="27" end="33" type="FORMAT_COMPRESSED"/>
     <field name="minlod" start="17" end="26" type="uint"/>
     <field name="swiz0" start="14" end="16" type="SWIZ"/>
@@ -325,7 +327,9 @@ SOFTWARE.
     <field name="texaddr_plane2_lo" start="50" end="63" shift="2" type="address"/>
     <field name="cmp_mode" start="59" end="61" type="CMP_MODE"/>
     <field name="addrmode_w" start="56" end="58" type="ADDRMODE"/>
-    <field name="bordercolor_index" start="50" end="55" type="uint"/>
+    <field name="bordercolor_index" start="50" end="55" type="uint">
+      <define name="MAX_SIZE" value="63"/>
+    </field>
     <field name="non_normalized_coords" start="49" end="49" type="bool"/>
     <field name="lumakey_alphamult" start="48" end="48" type="bool"/>
     <field name="lumakey" start="47" end="47" type="bool"/>
index fa034c9..6a16acf 100644 (file)
@@ -39,6 +39,7 @@ pvr_files = files(
   'winsys/pvr_winsys_helper.c',
   'pvr_blit.c',
   'pvr_bo.c',
+  'pvr_border.c',
   'pvr_clear.c',
   'pvr_cmd_buffer.c',
   'pvr_csb.c',
@@ -111,7 +112,7 @@ endif
 
 libvulkan_powervr_mesa = shared_library(
   'vulkan_powervr_mesa',
-  [pvr_files, pvr_entrypoints],
+  [pvr_files, pvr_entrypoints, u_format_pack_h],
   include_directories : [
     pvr_includes,
     inc_gallium_aux,
diff --git a/src/imagination/vulkan/pvr_border.c b/src/imagination/vulkan/pvr_border.c
new file mode 100644 (file)
index 0000000..f2d874f
--- /dev/null
@@ -0,0 +1,1147 @@
+/*
+ * Copyright © 2023 Imagination Technologies 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 <assert.h>
+#include <stdint.h>
+#include <vulkan/vulkan_core.h>
+
+#include "hwdef/rogue_hw_utils.h"
+#include "pvr_border.h"
+#include "pvr_csb.h"
+#include "pvr_device_info.h"
+#include "pvr_private.h"
+#include "util/bitset.h"
+#include "util/format_r11g11b10f.h"
+#include "util/format_rgb9e5.h"
+#include "util/format/format_utils.h"
+#include "util/format/u_format_pack.h"
+#include "util/macros.h"
+#include "util/u_endian.h"
+#include "vk_sampler.h"
+#include "vk_util.h"
+
+#define PVR_BORDER_COLOR_TABLE_NR_FORMATS \
+   (PVRX(TEXSTATE_IMAGE_WORD0_TEXFORMAT_MAX_SIZE) + 1)
+
+/* TODO: Eliminate all of these format-wrangling macros & functions by encoding
+ * our internal formats in a csv (a la src/mesa/main/formats.csv)
+ */
+
+#define intx(i, b) (i & BITFIELD_MASK(b))
+#define normx(n, b) _mesa_float_to_unorm(n, b)
+#define snormx(s, b) _mesa_float_to_snorm(s, b)
+
+#define int1(i) intx(i, 1)
+#define int2(i) intx(i, 2)
+#define int3(i) intx(i, 3)
+#define int4(i) intx(i, 4)
+#define int5(i) intx(i, 5)
+#define int6(i) intx(i, 6)
+#define int8(i) intx(i, 8)
+#define int10(i) intx(i, 10)
+#define int16(i) intx(i, 16)
+#define int24(i) intx(i, 24)
+#define int32(i) intx(i, 32)
+
+#define norm1(n) normx(n, 1)
+#define norm2(n) normx(n, 2)
+#define norm3(n) normx(n, 3)
+#define norm4(n) normx(n, 4)
+#define norm5(n) normx(n, 5)
+#define norm6(n) normx(n, 6)
+#define norm8(n) normx(n, 8)
+#define norm10(n) normx(n, 10)
+#define norm16(n) normx(n, 16)
+#define norm24(n) normx(n, 24)
+#define norm32(n) normx(n, 32)
+
+#define snorm5(s) snormx(s, 5)
+#define snorm8(s) snormx(s, 8)
+#define snorm16(s) snormx(s, 16)
+#define snorm32(s) snormx(s, 32)
+
+#define zero8 (0)
+#define zero10 (0)
+#define zero24 (0)
+#define zero32 (0)
+
+#define float10(f) f32_to_uf10(f)
+#define float11(f) f32_to_uf11(f)
+#define float16(f) ((uint32_t)_mesa_float_to_half(f))
+#define float32(f) ((uint32_t)(f))
+
+union pvr_border_color_table_value {
+   struct {
+      uint32_t w0, w1, w2, w3;
+   };
+   uint32_t arr[4];
+   uint8_t bytes[16];
+} PACKED;
+static_assert(sizeof(union pvr_border_color_table_value) ==
+                 4 * sizeof(uint32_t),
+              "pvr_border_color_table_value must be 4 x u32");
+
+struct pvr_border_color_table_entry {
+   union pvr_border_color_table_value formats[PVR_BORDER_COLOR_TABLE_NR_FORMATS];
+   union pvr_border_color_table_value
+      compressed_formats[PVR_BORDER_COLOR_TABLE_NR_FORMATS];
+} PACKED;
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i8(const uint32_t i0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int8(i0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i8i8(const uint32_t i0, const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int8(i0) | int8(i1) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i8i8i8(const uint32_t i0,
+                             const uint32_t i1,
+                             const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int8(i0) | int8(i1) << 8 | int8(i2) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i8i8i8i8(const uint32_t i0,
+                               const uint32_t i1,
+                               const uint32_t i2,
+                               const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int8(i0) | int8(i1) << 8 | int8(i2) << 16 | int8(i3) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i8i8i8x8(const uint32_t i0,
+                               const uint32_t i1,
+                               const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int8(i0) | int8(i1) << 8 | int8(i2) << 16 | zero8 << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i16(const uint32_t i0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int16(i0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i16i16(const uint32_t i0, const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int16(i0) | int16(i1) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i16i16i16(const uint32_t i0,
+                                const uint32_t i1,
+                                const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int16(i0) | int16(i1) << 16,
+      .w1 = int16(i2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i16i16i16i16(const uint32_t i0,
+                                   const uint32_t i1,
+                                   const uint32_t i2,
+                                   const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int16(i0) | int16(i1) << 16,
+      .w1 = int16(i2) | int16(i3) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i32(const uint32_t i0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int32(i0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i32i32(const uint32_t i0, const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int32(i0),
+      .w1 = int32(i1),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i32i32i32(const uint32_t i0,
+                                const uint32_t i1,
+                                const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int32(i0),
+      .w1 = int32(i1),
+      .w2 = int32(i2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i32i32i32i32(const uint32_t i0,
+                                   const uint32_t i1,
+                                   const uint32_t i2,
+                                   const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int32(i0),
+      .w1 = int32(i1),
+      .w2 = int32(i2),
+      .w3 = int32(i3),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i4i4i4i4(const uint32_t i0,
+                               const uint32_t i1,
+                               const uint32_t i2,
+                               const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int4(i0) | int4(i1) << 4 | int4(i2) << 8 | int4(i3) << 12,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i2i3i3i8(const uint32_t i0,
+                               const uint32_t i1,
+                               const uint32_t i2,
+                               const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int2(i0) | int3(i1) << 2 | int3(i2) << 5 | int8(i3) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i5i5i5i1(const uint32_t i0,
+                               const uint32_t i1,
+                               const uint32_t i2,
+                               const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int5(i0) | int5(i1) << 5 | int5(i2) << 10 | int1(i3) << 15,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i1i5i5i5(const uint32_t i0,
+                               const uint32_t i1,
+                               const uint32_t i2,
+                               const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int1(i0) | int5(i1) << 1 | int5(i2) << 6 | int5(i3) << 11,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i5i6i5(const uint32_t i0,
+                             const uint32_t i1,
+                             const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int5(i0) | int6(i1) << 5 | int5(i2) << 11,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i6i5i5(const uint32_t i0,
+                             const uint32_t i1,
+                             const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int6(i0) | int5(i1) << 6 | int5(i2) << 11,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i5i5i6(const uint32_t i0,
+                             const uint32_t i1,
+                             const uint32_t i2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int5(i0) | int5(i1) << 5 | int6(i2) << 10,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i10i10i10i2(const uint32_t i0,
+                                  const uint32_t i1,
+                                  const uint32_t i2,
+                                  const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int10(i0) | int10(i1) << 10 | int10(i2) << 20 | int2(i3) << 30,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_x10x10x10i2(const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = zero10 | zero10 << 10 | zero10 << 20 | int2(i3) << 30,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i2i10i10i10(const uint32_t i0,
+                                  const uint32_t i1,
+                                  const uint32_t i2,
+                                  const uint32_t i3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int2(i0) | int10(i1) << 2 | int10(i2) << 12 | int10(i3) << 22,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i2x10x10x10(const uint32_t i0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int2(i0) | zero10 << 2 | zero10 << 12 | zero10 << 22,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i24i8(const uint32_t i0, const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int24(i0) | int8(i1) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i24x8(const uint32_t i0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int24(i0) | zero8 << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_x24i8(const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = zero24 | int8(i1) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_i8i24(const uint32_t i0, const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = int8(i0) | int24(i1) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_x32i8x24(const uint32_t i1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = zero32,
+      .w1 = int8(i1) | zero24 << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8(const float n0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8n8(const float n0, const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0) | norm8(n1) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8n8n8(const float n0, const float n1, const float n2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0) | norm8(n1) << 8 | norm8(n2) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8n8n8n8(const float n0,
+                               const float n1,
+                               const float n2,
+                               const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0) | norm8(n1) << 8 | norm8(n2) << 16 | norm8(n3) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8n8n8x8(const float n0, const float n1, const float n2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0) | norm8(n1) << 8 | norm8(n2) << 16 | zero8 << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8s8s8x8(const float n0, const float s1, const float s2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0) | snorm8(s1) << 8 | snorm8(s2) << 16 | zero8 << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s8(const float s0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm8(s0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s8s8(const float s0, const float s1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm8(s0) | snorm8(s1) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s8s8s8(const float s0, const float s1, const float s2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm8(s0) | snorm8(s1) << 8 | snorm8(s2) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s8s8s8s8(const float s0,
+                               const float s1,
+                               const float s2,
+                               const float s3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm8(s0) | snorm8(s1) << 8 | snorm8(s2) << 16 | snorm8(s3) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n16(const float n0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm16(n0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n16n16(const float n0, const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm16(n0) | norm16(n1) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n16n16n16(const float n0, const float n1, const float n2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm16(n0) | norm16(n1) << 16,
+      .w1 = norm16(n2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n16n16n16n16(const float n0,
+                                   const float n1,
+                                   const float n2,
+                                   const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm16(n0) | norm16(n1) << 16,
+      .w1 = norm16(n2) | norm16(n3) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s16(const float s0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm16(s0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s16s16(const float s0, const float s1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm16(s0) | snorm16(s1) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s16s16s16(const float s0, const float s1, const float s2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm16(s0) | snorm16(s1) << 16,
+      .w1 = snorm16(s2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s16s16s16s16(const float s0,
+                                   const float s1,
+                                   const float s2,
+                                   const float s3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm16(s0) | snorm16(s1) << 16,
+      .w1 = snorm16(s2) | snorm16(s3) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n32(const float n0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm32(n0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n32n32(const float n0, const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm32(n0),
+      .w1 = norm32(n1),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n32n32n32(const float n0, const float n1, const float n2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm32(n0),
+      .w1 = norm32(n1),
+      .w2 = norm32(n2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n32n32n32n32(const float n0,
+                                   const float n1,
+                                   const float n2,
+                                   const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm32(n0),
+      .w1 = norm32(n1),
+      .w2 = norm32(n2),
+      .w3 = norm32(n3),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s32(const float s0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm32(s0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s32s32(const float s0, const float s1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm32(s0),
+      .w1 = snorm32(s1),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s32s32s32(const float s0, const float s1, const float s2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm32(s0),
+      .w1 = snorm32(s1),
+      .w2 = snorm32(s2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s32s32s32s32(const float s0,
+                                   const float s1,
+                                   const float s2,
+                                   const float s3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm32(s0),
+      .w1 = snorm32(s1),
+      .w2 = snorm32(s2),
+      .w3 = snorm32(s3),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n4n4n4n4(const float n0,
+                               const float n1,
+                               const float n2,
+                               const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm4(n0) | norm4(n1) << 4 | norm4(n2) << 8 | norm4(n3) << 12,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n2n3n3n8(const float n0,
+                               const float n1,
+                               const float n2,
+                               const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm2(n0) | norm3(n1) << 2 | norm3(n2) << 5 | norm8(n3) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n5n5n5n1(const float n0,
+                               const float n1,
+                               const float n2,
+                               const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm5(n0) | norm5(n1) << 5 | norm5(n2) << 10 | norm1(n3) << 15,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n1n5n5n5(const float n0,
+                               const float n1,
+                               const float n2,
+                               const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm1(n0) | norm5(n1) << 1 | norm5(n2) << 6 | norm5(n3) << 11,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n5n6n5(const float n0, const float n1, const float n2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm5(n0) | norm6(n1) << 5 | norm5(n2) << 11,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n6s5s5(const float n0, const float s1, const float s2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm6(n0) | snorm5(s1) << 6 | snorm5(s2) << 11,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_s5s5n6(const float s0, const float s1, const float n2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = snorm5(s0) | snorm5(s1) << 5 | norm6(n2) << 10,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n10n10n10n2(const float n0,
+                                  const float n1,
+                                  const float n2,
+                                  const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm10(n0) | norm10(n1) << 10 | norm10(n2) << 20 | norm2(n3) << 30,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f10f10f10n2(const float f0,
+                                  const float f1,
+                                  const float f2,
+                                  const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float10(f0) | float10(f1) << 10 | float10(f2) << 20 |
+            norm2(n3) << 30,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n2n10n10n10(const float n0,
+                                  const float n1,
+                                  const float n2,
+                                  const float n3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm2(n0) | norm10(n1) << 2 | norm10(n2) << 12 | norm10(n3) << 22,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n2f10f10f10(const float n0,
+                                  const float f1,
+                                  const float f2,
+                                  const float f3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm2(n0) | float10(f1) << 2 | float10(f2) << 12 |
+            float10(f3) << 22,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n24n8(const float n0, const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm24(n0) | norm8(n1) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n24x8(const float n0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm24(n0) | zero8 << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_x24n8(const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = zero24 | norm8(n1) << 24,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_n8n24(const float n0, const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = norm8(n0) | norm24(n1) << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f32n8x24(const float f0, const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(f0),
+      .w1 = norm8(n1) | zero24 << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f32x8x24(const float f0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(f0),
+      .w1 = zero8 | zero24 << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_x32n8x24(const float n1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = zero32,
+      .w1 = norm8(n1) | zero24 << 8,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f16(const float f0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float16(f0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f16f16(const float f0, const float f1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float16(f0) | float16(f1) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f16f16f16(const float f0, const float f1, const float f2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float16(f0) | float16(f1) << 16,
+      .w1 = float16(f2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f16f16f16f16(const float f0,
+                                   const float f1,
+                                   const float f2,
+                                   const float f3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float16(f0) | float16(f1) << 16,
+      .w1 = float16(f2) | float16(f3) << 16,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f32(const float f0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(f0),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_g32(const float g0)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(g0) & 0x7fffffff,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f32f32(const float f0, const float f1)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(f0),
+      .w1 = float32(f1),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f32f32f32(const float f0, const float f1, const float f2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(f0),
+      .w1 = float32(f1),
+      .w2 = float32(f2),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f32f32f32f32(const float f0,
+                                   const float f1,
+                                   const float f2,
+                                   const float f3)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float32(f0),
+      .w1 = float32(f1),
+      .w2 = float32(f2),
+      .w3 = float32(f3),
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f10f11f11(const float f0, const float f1, const float f2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float10(f0) | float11(f1) << 10 | float11(f2) << 21,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_f11f11f10(const float f0, const float f1, const float f2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float11(f0) | float11(f1) << 11 | float10(f2) << 22,
+   };
+}
+
+static inline union pvr_border_color_table_value
+pvr_pack_border_color_e9e9e9x5(const float f0, const float f1, const float f2)
+{
+   return (union pvr_border_color_table_value){
+      .w0 = float3_to_rgb9e5((float[3]){ f0, f1, f2 }),
+   };
+}
+
+#define PACK(format_, layout_, channels_...)         \
+   entry->formats[PVRX(TEXSTATE_FORMAT_##format_)] = \
+      pvr_pack_border_color_##layout_(channels_)
+
+/* clang-format off */
+#define UDEF(format_)                                \
+   entry->formats[PVRX(TEXSTATE_FORMAT_##format_)] = \
+      (union pvr_border_color_table_value){ 0 }
+/* clang-format on */
+
+static void
+pvr_pack_border_color_ints(struct pvr_border_color_table_entry *const entry,
+                           const uint32_t color[const static 4])
+{
+   const uint32_t r = color[0];
+   const uint32_t g = color[1];
+   const uint32_t b = color[2];
+   const uint32_t a = color[3];
+
+   /*   0 */ PACK(U8, i8, r);
+   /*   1 */ PACK(S8, i8, r);
+   /*   7 */ PACK(U8U8, i8i8, g, r);
+   /*   8 */ PACK(S8S8, i8i8, g, r);
+   /*   9 */ PACK(U16, i16, r);
+   /*  10 */ PACK(S16, i16, r);
+   /*  11 */ UDEF(F16);
+   /*  12 */ PACK(U8U8U8U8, i8i8i8i8, a, b, g, r);
+   /*  13 */ PACK(S8S8S8S8, i8i8i8i8, a, b, g, r);
+   /*  14 */ PACK(A2R10B10G10, i10i10i10i2, r, g, b, a);
+   /*  15 */ PACK(U16U16, i16i16, g, r);
+   /*  16 */ PACK(S16S16, i16i16, g, r);
+   /*  17 */ UDEF(F16F16);
+   /*  18 */ UDEF(F32);
+   /*  22 */ PACK(ST8U24, i24i8, g, r);
+   /*  23 */ PACK(U8X24, x24i8, r);
+   /*  24 */ PACK(U32, i32, r);
+   /*  25 */ PACK(S32, i32, r);
+   /*  26 */ UDEF(SE9995);
+   /*  28 */ UDEF(F16F16F16F16);
+   /*  29 */ PACK(U16U16U16U16, i16i16i16i16, a, b, g, r);
+   /*  30 */ PACK(S16S16S16S16, i16i16i16i16, a, b, g, r);
+   /*  35 */ PACK(U32U32, i32i32, g, r);
+   /*  36 */ PACK(S32S32, i32i32, g, r);
+   /*  61 */ UDEF(F32F32F32F32);
+   /*  62 */ PACK(U32U32U32U32, i32i32i32i32, a, b, g, r);
+   /*  63 */ PACK(S32S32S32S32, i32i32i32i32, a, b, g, r);
+   /*  64 */ UDEF(F32F32F32);
+   /*  65 */ PACK(U32U32U32, i32i32i32, b, g, r);
+   /*  66 */ PACK(S32S32S32, i32i32i32, b, g, r);
+   /*  88 */ UDEF(F10F11F11);
+}
+
+static void
+pvr_pack_border_color_floats(struct pvr_border_color_table_entry *const entry,
+                             const float color[const static 4])
+{
+   const float r = color[0];
+   const float g = color[1];
+   const float b = color[2];
+   const float a = color[3];
+
+   /*   0 */ PACK(U8, n8, r);
+   /*   1 */ PACK(S8, s8, r);
+   /*   2 */ PACK(A4R4G4B4, n4n4n4n4, b, g, r, a);
+   /*   4 */ PACK(A1R5G5B5, n5n5n5n1, b, g, r, a);
+   /*   5 */ PACK(R5G6B5, n5n6n5, b, g, r);
+   /*   7 */ PACK(U8U8, n8n8, g, r);
+   /*   8 */ PACK(S8S8, s8s8, g, r);
+   /*   9 */ PACK(U16, n16, r);
+   /*  10 */ PACK(S16, s16, r);
+   /*  11 */ PACK(F16, f16, r);
+   /*  12 */ PACK(U8U8U8U8, n8n8n8n8, a, b, g, r);
+   /*  13 */ PACK(S8S8S8S8, s8s8s8s8, a, b, g, r);
+   /*  14 */ PACK(A2R10B10G10, n10n10n10n2, r, g, b, a);
+   /*  15 */ PACK(U16U16, n16n16, g, r);
+   /*  16 */ PACK(S16S16, s16s16, g, r);
+   /*  17 */ PACK(F16F16, f16f16, g, r);
+   /*  18 */ PACK(F32, f32, r);
+   /*  22 */ PACK(ST8U24, n24n8, g, r);
+   /*  26 */ PACK(SE9995, e9e9e9x5, r, g, b);
+   /*  28 */ PACK(F16F16F16F16, f16f16f16f16, a, b, g, r);
+   /*  29 */ PACK(U16U16U16U16, n16n16n16n16, a, b, g, r);
+   /*  30 */ PACK(S16S16S16S16, s16s16s16s16, a, b, g, r);
+   /*  34 */ PACK(F32F32, f32f32, g, r);
+   /*  61 */ PACK(F32F32F32F32, f32f32f32f32, a, b, g, r);
+   /*  64 */ PACK(F32F32F32, f32f32f32, b, g, r);
+   /*  88 */ PACK(F10F11F11, f11f11f10, b, g, r);
+}
+
+#undef PACK
+#undef UDEF
+
+#define PACKC(format_, layout_, channels_...)                              \
+   entry->compressed_formats[PVRX(TEXSTATE_FORMAT_COMPRESSED_##format_)] = \
+      pvr_pack_border_color_##layout_(channels_)
+
+static void pvr_pack_border_color_compressed(
+   struct pvr_border_color_table_entry *const entry,
+   const VkClearColorValue color[const static 4])
+{
+   const uint32_t r = color->uint32[0];
+   const uint32_t g = color->uint32[1];
+   const uint32_t b = color->uint32[2];
+   const uint32_t a = color->uint32[3];
+
+   /*  68 */ PACKC(ETC2_RGB, i8i8i8i8, a, b, g, r);
+   /*  69 */ PACKC(ETC2A_RGBA, i8i8i8i8, a, b, g, r);
+   /*  70 */ PACKC(ETC2_PUNCHTHROUGHA, i8i8i8i8, a, b, g, r);
+   /*  71 */ PACKC(EAC_R11_UNSIGNED, i16i16i16i16, a, b, g, r);
+   /*  72 */ PACKC(EAC_R11_SIGNED, i16i16i16i16, a, b, g, r);
+   /*  73 */ PACKC(EAC_RG11_UNSIGNED, i16i16i16i16, a, b, g, r);
+   /*  74 */ PACKC(EAC_RG11_SIGNED, i16i16i16i16, a, b, g, r);
+}
+
+#undef PACKC
+
+static int32_t
+pvr_border_color_table_alloc_entry(struct pvr_border_color_table *const table)
+{
+   const int32_t index = BITSET_FFS(table->unused_entries);
+
+   /* BITSET_FFS() returns 0 if there are no set bits; we have to determine
+    * whether a value of 0 means "no set bits" or "zero is the first set bit".
+    */
+   if (index == 0 && !pvr_border_color_table_is_index_valid(table, 0)) {
+      return -1;
+   }
+
+   BITSET_CLEAR(table->unused_entries, index);
+
+   return index;
+}
+
+static void
+pvr_border_color_table_free_entry(struct pvr_border_color_table *const table,
+                                  const uint32_t index)
+{
+   assert(BITSET_TEST(table->unused_entries, index));
+   BITSET_SET(table->unused_entries, index);
+}
+
+static void
+pvr_border_color_table_fill_entry(struct pvr_border_color_table *const table,
+                                  const struct pvr_device *const device,
+                                  const uint32_t index,
+                                  const VkClearColorValue *const color,
+                                  const bool is_int)
+{
+   struct pvr_border_color_table_entry *const entries = table->table->bo->map;
+   const struct pvr_device_info *const dev_info = &device->pdevice->dev_info;
+   struct pvr_border_color_table_entry *entry;
+
+   assert(pvr_border_color_table_is_index_valid(table, index));
+   assert(entries);
+
+   entry = &entries[index];
+   memset(entry, 0, sizeof(*entry));
+
+   if (is_int)
+      pvr_pack_border_color_ints(entry, color->uint32);
+   else
+      pvr_pack_border_color_floats(entry, color->float32);
+
+   if (PVR_HAS_FEATURE(dev_info, tpu_border_colour_enhanced)) {
+      pvr_pack_border_color_compressed(entry, color);
+   } else {
+      pvr_finishme("Devices without tpu_border_colour_enhanced require entries "
+                   "for compressed formats to be stored in the table "
+                   "pre-compressed.");
+   }
+}
+
+VkResult pvr_border_color_table_init(struct pvr_border_color_table *const table,
+                                     struct pvr_device *const device)
+{
+   const struct pvr_device_info *const dev_info = &device->pdevice->dev_info;
+   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
+   const uint32_t table_size = sizeof(struct pvr_border_color_table_entry) *
+                               PVR_BORDER_COLOR_TABLE_NR_ENTRIES;
+
+   VkResult result;
+
+   /* Initialize to ones so ffs can be used to find unused entries. */
+   BITSET_ONES(table->unused_entries);
+
+   result = pvr_bo_alloc(device,
+                         device->heaps.general_heap,
+                         table_size,
+                         cache_line_size,
+                         PVR_BO_ALLOC_FLAG_CPU_MAPPED,
+                         &table->table);
+   if (result != VK_SUCCESS)
+      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   BITSET_CLEAR_RANGE(table->unused_entries,
+                      0,
+                      PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES - 1);
+
+   for (uint32_t i = 0; i < PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES; i++) {
+      const VkClearColorValue color = vk_border_color_value(i);
+      const bool is_int = vk_border_color_is_int(i);
+
+      pvr_border_color_table_fill_entry(table, device, i, &color, is_int);
+   }
+
+   pvr_bo_cpu_unmap(device, table->table);
+
+   return VK_SUCCESS;
+}
+
+void pvr_border_color_table_finish(struct pvr_border_color_table *const table,
+                                   struct pvr_device *const device)
+{
+   pvr_bo_free(device, table->table);
+}
+
+VkResult pvr_border_color_table_get_or_create_entry(
+   UNUSED struct pvr_border_color_table *const table,
+   const struct VkSamplerCreateInfo *const sampler_create_info,
+   uint32_t *const index_out)
+{
+   const VkBorderColor vk_type = sampler_create_info->borderColor;
+
+   if (vk_type <= PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES) {
+      *index_out = vk_type;
+      return VK_SUCCESS;
+   }
+
+   pvr_finishme("VK_EXT_custom_border_color is currently unsupported.");
+   return vk_error(NULL, VK_ERROR_EXTENSION_NOT_PRESENT);
+}
diff --git a/src/imagination/vulkan/pvr_border.h b/src/imagination/vulkan/pvr_border.h
new file mode 100644 (file)
index 0000000..4c190f0
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2023 Imagination Technologies 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 PVR_BORDER_H
+#define PVR_BORDER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <vulkan/vulkan_core.h>
+
+#include "pvr_csb.h"
+#include "util/bitset.h"
+
+#define PVR_BORDER_COLOR_TABLE_NR_ENTRIES \
+   (PVRX(TEXSTATE_SAMPLER_BORDERCOLOR_INDEX_MAX_SIZE) + 1)
+
+#define PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES \
+   (VK_BORDER_COLOR_INT_OPAQUE_WHITE + 1U)
+
+#define PVR_BORDER_COLOR_TABLE_NR_CUSTOM_ENTRIES \
+   (PVR_BORDER_COLOR_TABLE_NR_ENTRIES -          \
+    PVR_BORDER_COLOR_TABLE_NR_BUILTIN_ENTRIES)
+
+/* Forward declaration from "pvr_bo.h" */
+struct pvr_bo;
+
+/* Forward declaration from "pvr_private.h" */
+struct pvr_device;
+
+struct pvr_border_color_table {
+   BITSET_DECLARE(unused_entries, PVR_BORDER_COLOR_TABLE_NR_ENTRIES);
+
+   /* Contains an array of:
+    * PVR_BORDER_COLOR_TABLE_NR_ENTRIES x struct pvr_border_color_table_entry
+    */
+   struct pvr_bo *table;
+};
+
+VkResult pvr_border_color_table_init(struct pvr_border_color_table *table,
+                                     struct pvr_device *device);
+void pvr_border_color_table_finish(struct pvr_border_color_table *table,
+                                   struct pvr_device *device);
+
+VkResult pvr_border_color_table_get_or_create_entry(
+   struct pvr_border_color_table *table,
+   const struct VkSamplerCreateInfo *sampler_create_info,
+   uint32_t *index_out);
+
+static inline bool pvr_border_color_table_is_index_valid(
+   const struct pvr_border_color_table *const table,
+   const uint32_t index)
+{
+   return !BITSET_TEST(table->unused_entries, index);
+}
+
+#endif /* PVR_BORDER_H */
index a52f439..ac6b75d 100644 (file)
@@ -1436,11 +1436,6 @@ static VkResult pvr_sub_cmd_gfx_job_init(const struct pvr_device_info *dev_info,
 
    job->ctrl_stream_addr = pvr_csb_get_start_address(&sub_cmd->control_stream);
 
-   /* FIXME: Need to set up the border color table at device creation
-    * time. Set to invalid for the time being.
-    */
-   job->border_colour_table_addr = PVR_DEV_ADDR_INVALID;
-
    if (sub_cmd->depth_bias_bo)
       job->depth_bias_table_addr = sub_cmd->depth_bias_bo->dev_addr;
    else
index f533daa..2aede42 100644 (file)
@@ -41,6 +41,7 @@
 #include "hwdef/rogue_hw_utils.h"
 #include "pipe/p_defines.h"
 #include "pvr_bo.h"
+#include "pvr_border.h"
 #include "pvr_clear.h"
 #include "pvr_csb.h"
 #include "pvr_csb_enum_helpers.h"
@@ -1876,6 +1877,10 @@ VkResult pvr_CreateDevice(VkPhysicalDevice physicalDevice,
    if (result != VK_SUCCESS)
       goto err_pvr_spm_finish_scratch_buffer_store;
 
+   result = pvr_border_color_table_init(&device->border_color_table, device);
+   if (result != VK_SUCCESS)
+      goto err_pvr_robustness_buffer_finish;
+
    /* FIXME: Move this to a later stage and possibly somewhere other than
     * pvr_device. The purpose of this is so that we don't have to get the size
     * on each kick.
@@ -1891,6 +1896,9 @@ VkResult pvr_CreateDevice(VkPhysicalDevice physicalDevice,
 
    return VK_SUCCESS;
 
+err_pvr_robustness_buffer_finish:
+   pvr_robustness_buffer_finish(device);
+
 err_pvr_spm_finish_scratch_buffer_store:
    pvr_spm_finish_scratch_buffer_store(device);
 
@@ -1954,6 +1962,7 @@ void pvr_DestroyDevice(VkDevice _device,
    if (!device)
       return;
 
+   pvr_border_color_table_finish(&device->border_color_table, device);
    pvr_robustness_buffer_finish(device);
    pvr_spm_finish_scratch_buffer_store(device);
    pvr_queues_destroy(device);
@@ -2987,10 +2996,12 @@ VkResult pvr_CreateSampler(VkDevice _device,
                            VkSampler *pSampler)
 {
    PVR_FROM_HANDLE(pvr_device, device, _device);
+   uint32_t border_color_table_index;
    struct pvr_sampler *sampler;
    float lod_rounding_bias;
    VkFilter min_filter;
    VkFilter mag_filter;
+   VkResult result;
    float min_lod;
    float max_lod;
 
@@ -3001,12 +3012,21 @@ VkResult pvr_CreateSampler(VkDevice _device,
                              pAllocator,
                              sizeof(*sampler),
                              VK_OBJECT_TYPE_SAMPLER);
-   if (!sampler)
-      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+   if (!sampler) {
+      result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
+      goto err_out;
+   }
 
    mag_filter = pCreateInfo->magFilter;
    min_filter = pCreateInfo->minFilter;
 
+   result =
+      pvr_border_color_table_get_or_create_entry(&device->border_color_table,
+                                                 pCreateInfo,
+                                                 &border_color_table_index);
+   if (result != VK_SUCCESS)
+      goto err_free_sampler;
+
    if (PVR_HAS_QUIRK(&device->pdevice->dev_info, 51025)) {
       /* The min/mag filters may need adjustment here, the GPU should decide
        * which of the two filters to use based on the clamped LOD value: LOD
@@ -3108,7 +3128,7 @@ VkResult pvr_CreateSampler(VkDevice _device,
       word.maxlod = util_unsigned_fixed(CLAMP(max_lod, 0.0f, lod_clamp_max),
                                         PVRX(TEXSTATE_CLAMP_FRACTIONAL_BITS));
 
-      word.bordercolor_index = pCreateInfo->borderColor;
+      word.bordercolor_index = border_color_table_index;
 
       if (pCreateInfo->unnormalizedCoordinates)
          word.non_normalized_coords = true;
@@ -3117,6 +3137,12 @@ VkResult pvr_CreateSampler(VkDevice _device,
    *pSampler = pvr_sampler_to_handle(sampler);
 
    return VK_SUCCESS;
+
+err_free_sampler:
+   vk_object_free(&device->vk, pAllocator, sampler);
+
+err_out:
+   return result;
 }
 
 void pvr_DestroySampler(VkDevice _device,
index c22960b..ef00dd6 100644 (file)
@@ -41,7 +41,8 @@ pvr_submit_info_stream_init(struct pvr_compute_ctx *ctx,
                             struct pvr_sub_cmd_compute *sub_cmd,
                             struct pvr_winsys_compute_submit_info *submit_info)
 {
-   const struct pvr_physical_device *const pdevice = ctx->device->pdevice;
+   const struct pvr_device *const device = ctx->device;
+   const struct pvr_physical_device *const pdevice = device->pdevice;
    const struct pvr_device_runtime_info *const dev_runtime_info =
       &pdevice->dev_runtime_info;
    const struct pvr_device_info *const dev_info = &pdevice->dev_info;
@@ -49,13 +50,11 @@ pvr_submit_info_stream_init(struct pvr_compute_ctx *ctx,
 
    uint32_t *stream_ptr = (uint32_t *)submit_info->fw_stream;
 
-   /* FIXME: Need to set up the border color table at device creation time. Set
-    * to invalid for the time being.
-    */
    pvr_csb_pack ((uint64_t *)stream_ptr,
                  CR_TPU_BORDER_COLOUR_TABLE_CDM,
                  value) {
-      value.border_colour_table_address = PVR_DEV_ADDR_INVALID;
+      value.border_colour_table_address =
+         device->border_color_table.table->vma->dev_addr;
    }
    stream_ptr += pvr_cmd_length(CR_TPU_BORDER_COLOUR_TABLE_CDM);
 
index b8ab0c9..d325e1f 100644 (file)
@@ -938,7 +938,8 @@ static void pvr_geom_state_stream_init(struct pvr_render_ctx *ctx,
                                        struct pvr_render_job *job,
                                        struct pvr_winsys_geometry_state *state)
 {
-   const struct pvr_device_info *dev_info = &ctx->device->pdevice->dev_info;
+   const struct pvr_device *const device = ctx->device;
+   const struct pvr_device_info *const dev_info = &device->pdevice->dev_info;
 
    uint32_t *stream_ptr = (uint32_t *)state->fw_stream;
 
@@ -950,7 +951,8 @@ static void pvr_geom_state_stream_init(struct pvr_render_ctx *ctx,
    pvr_csb_pack ((uint64_t *)stream_ptr,
                  CR_TPU_BORDER_COLOUR_TABLE_VDM,
                  value) {
-      value.border_colour_table_address = job->border_colour_table_addr;
+      value.border_colour_table_address =
+         device->border_color_table.table->vma->dev_addr;
    }
    stream_ptr += pvr_cmd_length(CR_TPU_BORDER_COLOUR_TABLE_VDM);
 
@@ -1058,7 +1060,8 @@ static void pvr_frag_state_stream_init(struct pvr_render_ctx *ctx,
                                        struct pvr_render_job *job,
                                        struct pvr_winsys_fragment_state *state)
 {
-   const struct pvr_physical_device *const pdevice = ctx->device->pdevice;
+   const struct pvr_device *const device = ctx->device;
+   const struct pvr_physical_device *const pdevice = device->pdevice;
    const struct pvr_device_runtime_info *dev_runtime_info =
       &pdevice->dev_runtime_info;
    const struct pvr_device_info *dev_info = &pdevice->dev_info;
@@ -1203,7 +1206,8 @@ static void pvr_frag_state_stream_init(struct pvr_render_ctx *ctx,
    pvr_csb_pack ((uint64_t *)stream_ptr,
                  CR_TPU_BORDER_COLOUR_TABLE_PDM,
                  value) {
-      value.border_colour_table_address = job->border_colour_table_addr;
+      value.border_colour_table_address =
+         device->border_color_table.table->vma->dev_addr;
    }
    stream_ptr += pvr_cmd_length(CR_TPU_BORDER_COLOUR_TABLE_PDM);
 
index 5754306..a214d5e 100644 (file)
@@ -88,7 +88,6 @@ struct pvr_render_job {
 
    pvr_dev_addr_t ctrl_stream_addr;
 
-   pvr_dev_addr_t border_colour_table_addr;
    pvr_dev_addr_t depth_bias_table_addr;
    pvr_dev_addr_t scissor_table_addr;
 
index b691411..19e7507 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "compiler/shader_enums.h"
 #include "hwdef/rogue_hw_defs.h"
+#include "pvr_border.h"
 #include "pvr_clear.h"
 #include "pvr_common.h"
 #include "pvr_csb.h"
@@ -277,6 +278,8 @@ struct pvr_device {
    struct pvr_bo *robustness_buffer;
 
    struct vk_sync *presignaled_sync;
+
+   struct pvr_border_color_table border_color_table;
 };
 
 struct pvr_device_memory {