diff --git a/hw/xbox/nv2a/nv2a_int.h b/hw/xbox/nv2a/nv2a_int.h
index 28731c8b6b..c8eb214d95 100644
--- a/hw/xbox/nv2a/nv2a_int.h
+++ b/hw/xbox/nv2a/nv2a_int.h
@@ -284,9 +284,6 @@ typedef struct PGRAPHState {
 
     bool texture_matrix_enable[NV2A_MAX_TEXTURES];
 
-    /* FIXME: Move to NV_PGRAPH_BUMPMAT... */
-    float bump_env_matrix[NV2A_MAX_TEXTURES - 1][4]; /* 3 allowed stages with 2x2 matrix each */
-
     GLuint gl_framebuffer;
 
     GLuint gl_display_buffer;
diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h
index dde8da47a5..de5d30cb05 100644
--- a/hw/xbox/nv2a/nv2a_regs.h
+++ b/hw/xbox/nv2a/nv2a_regs.h
@@ -377,6 +377,10 @@
 #define NV_PGRAPH_BORDERCOLOR1                           0x00001810
 #define NV_PGRAPH_BORDERCOLOR2                           0x00001814
 #define NV_PGRAPH_BORDERCOLOR3                           0x00001818
+#define NV_PGRAPH_BUMPMAT00                              0x0000181C
+#define NV_PGRAPH_BUMPMAT01                              0x00001828
+#define NV_PGRAPH_BUMPMAT10                              0x00001834
+#define NV_PGRAPH_BUMPMAT11                              0x00001840
 #define NV_PGRAPH_BUMPOFFSET1                            0x0000184C
 #define NV_PGRAPH_BUMPSCALE1                             0x00001858
 #define NV_PGRAPH_CLEARRECTX                             0x00001864
diff --git a/hw/xbox/nv2a/pgraph.c b/hw/xbox/nv2a/pgraph.c
index 81c1960a20..28b0164800 100644
--- a/hw/xbox/nv2a/pgraph.c
+++ b/hw/xbox/nv2a/pgraph.c
@@ -2796,7 +2796,9 @@ DEF_METHOD(NV097, SET_TEXTURE_SET_BUMP_ENV_MAT)
     }
 
     slot -= 16;
-    pg->bump_env_matrix[slot / 16][slot % 4] = *(float*)&parameter;
+    const int swizzle[4] = { NV_PGRAPH_BUMPMAT00, NV_PGRAPH_BUMPMAT01,
+                             NV_PGRAPH_BUMPMAT11, NV_PGRAPH_BUMPMAT10 };
+    pg->regs[swizzle[slot % 4] + slot / 4] = parameter;
 }
 
 DEF_METHOD(NV097, SET_TEXTURE_SET_BUMP_ENV_SCALE)
@@ -3625,7 +3627,12 @@ static void pgraph_shader_update_constants(PGRAPHState *pg,
         if (i > 0) {
             loc = binding->bump_mat_loc[i];
             if (loc != -1) {
-                glUniformMatrix2fv(loc, 1, GL_FALSE, pg->bump_env_matrix[i - 1]);
+                float m[4];
+                m[0] = *(float*)&pg->regs[NV_PGRAPH_BUMPMAT00 + 4 * (i - 1)];
+                m[1] = *(float*)&pg->regs[NV_PGRAPH_BUMPMAT01 + 4 * (i - 1)];
+                m[2] = *(float*)&pg->regs[NV_PGRAPH_BUMPMAT10 + 4 * (i - 1)];
+                m[3] = *(float*)&pg->regs[NV_PGRAPH_BUMPMAT11 + 4 * (i - 1)];
+                glUniformMatrix2fv(loc, 1, GL_FALSE, m);
             }
             loc = binding->bump_scale_loc[i];
             if (loc != -1) {
diff --git a/hw/xbox/nv2a/psh.c b/hw/xbox/nv2a/psh.c
index a166d148e5..e00ace33af 100644
--- a/hw/xbox/nv2a/psh.c
+++ b/hw/xbox/nv2a/psh.c
@@ -730,8 +730,7 @@ static MString* psh_convert(struct PixelShader *ps)
                                    i, ps->input_tex[i], ps->input_tex[i]);
             }
 
-            /* FIXME: Do bumpMat swizzle on CPU before upload */
-            mstring_append_fmt(vars, "dsdt%d = mat2(bumpMat%d[0].xy, bumpMat%d[1].yx) * dsdt%d;\n",
+            mstring_append_fmt(vars, "dsdt%d = bumpMat%d * dsdt%d;\n",
                 i, i, i, i);
             mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * (pT%d.xy + dsdt%d));\n",
                 i, i, i, i, i);
@@ -753,8 +752,7 @@ static MString* psh_convert(struct PixelShader *ps)
                                    i, ps->input_tex[i], ps->input_tex[i], ps->input_tex[i]);
             }
 
-            /* FIXME: Do bumpMat swizzle on CPU before upload */
-            mstring_append_fmt(vars, "dsdtl%d.st = mat2(bumpMat%d[0].xy, bumpMat%d[1].yx) * dsdtl%d.st;\n",
+            mstring_append_fmt(vars, "dsdtl%d.st = bumpMat%d * dsdtl%d.st;\n",
                 i, i, i, i);
             mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, texScale%d * (pT%d.xy + dsdtl%d.st));\n",
                 i, i, i, i, i);