summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/etnaviv/etnaviv_shader.c
diff options
context:
space:
mode:
authorWladimir J. van der Laan <[email protected]>2017-07-24 10:28:17 +0200
committerChristian Gmeiner <[email protected]>2017-08-06 20:44:02 +0200
commit39056b0e2ac10342d8a3a6000f12a510f5dbd773 (patch)
tree2af42477d466d63ab23518123737f70b0e52e760 /src/gallium/drivers/etnaviv/etnaviv_shader.c
parent6c321c8b0b3547b0af0b0939391eef4dc8d2f873 (diff)
etnaviv: Implement ICACHE
This patch adds support for large shaders on GC3000. For example the "terrain" glmark benchmark with a large fragment shader will work after this. If the GPU supports ICACHE, shaders larger than the available state area will be uploaded to a bo of their own and instructed to be loaded from memory on demand. Small shaders will be uploaded in the usual way. This mimics the behavior of the blob. On GPUs that don't support ICACHE, this patch should make no difference. Signed-off-by: Wladimir J. van der Laan <[email protected]> Reviewed-by: Christian Gmeiner <[email protected]>
Diffstat (limited to 'src/gallium/drivers/etnaviv/etnaviv_shader.c')
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_shader.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
index b5256e4b510..6012680624b 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
@@ -29,12 +29,30 @@
#include "etnaviv_compiler.h"
#include "etnaviv_context.h"
#include "etnaviv_debug.h"
+#include "etnaviv_screen.h"
#include "etnaviv_util.h"
#include "tgsi/tgsi_parse.h"
#include "util/u_math.h"
#include "util/u_memory.h"
+/* Upload shader code to bo, if not already done */
+static bool etna_icache_upload_shader(struct etna_context *ctx, struct etna_shader_variant *v)
+{
+ if (v->bo)
+ return true;
+ v->bo = etna_bo_new(ctx->screen->dev, v->code_size*4, DRM_ETNA_GEM_CACHE_UNCACHED);
+ if (!v->bo)
+ return false;
+
+ void *buf = etna_bo_map(v->bo);
+ etna_bo_cpu_prep(v->bo, DRM_ETNA_PREP_WRITE);
+ memcpy(buf, v->code, v->code_size*4);
+ etna_bo_cpu_fini(v->bo);
+ DBG("Uploaded %s of %u words to bo %p", v->processor == PIPE_SHADER_FRAGMENT ? "fs":"vs", v->code_size, v->bo);
+ return true;
+}
+
/* Link vs and fs together: fill in shader_state from vs and fs
* as this function is called every time a new fs or vs is bound, the goal is to
* do little processing as possible here, and to precompute as much as possible in
@@ -45,7 +63,7 @@
*/
static bool
etna_link_shaders(struct etna_context *ctx, struct compiled_shader_state *cs,
- const struct etna_shader_variant *vs, const struct etna_shader_variant *fs)
+ struct etna_shader_variant *vs, struct etna_shader_variant *fs)
{
struct etna_shader_link_info link = { };
@@ -164,9 +182,32 @@ etna_link_shaders(struct etna_context *ctx, struct compiled_shader_state *cs,
/* reference instruction memory */
cs->vs_inst_mem_size = vs->code_size;
cs->VS_INST_MEM = vs->code;
+
cs->ps_inst_mem_size = fs->code_size;
cs->PS_INST_MEM = fs->code;
+ if (vs->needs_icache | fs->needs_icache) {
+ /* If either of the shaders needs ICACHE, we use it for both. It is
+ * either switched on or off for the entire shader processor.
+ */
+ if (!etna_icache_upload_shader(ctx, vs) ||
+ !etna_icache_upload_shader(ctx, fs)) {
+ assert(0);
+ return false;
+ }
+
+ cs->VS_INST_ADDR.bo = vs->bo;
+ cs->VS_INST_ADDR.offset = 0;
+ cs->VS_INST_ADDR.flags = ETNA_RELOC_READ;
+ cs->PS_INST_ADDR.bo = fs->bo;
+ cs->PS_INST_ADDR.offset = 0;
+ cs->PS_INST_ADDR.flags = ETNA_RELOC_READ;
+ } else {
+ /* clear relocs */
+ memset(&cs->VS_INST_ADDR, 0, sizeof(cs->VS_INST_ADDR));
+ memset(&cs->PS_INST_ADDR, 0, sizeof(cs->PS_INST_ADDR));
+ }
+
return true;
}
@@ -352,6 +393,8 @@ etna_delete_shader_state(struct pipe_context *pctx, void *ss)
while (v) {
t = v;
v = v->next;
+ if (t->bo)
+ etna_bo_del(t->bo);
etna_destroy_shader(t);
}