diff --git a/nx/include/switch/display/gfx.h b/nx/include/switch/display/gfx.h
index 0e70d9e0..060d48a5 100644
--- a/nx/include/switch/display/gfx.h
+++ b/nx/include/switch/display/gfx.h
@@ -73,6 +73,9 @@ void gfxWaitForVsync(void);
 /// Swaps the framebuffers (for double-buffering).
 void gfxSwapBuffers(void);
 
+/// Get the current framebuffer nvmap handle, with optional output ptrs for the current offset in the buffer.
+u32 gfxGetFramebufferHandle(u32* offset);
+
 /// Get the current framebuffer address, with optional output ptrs for the display framebuffer width/height. The display width/height is adjusted by \ref gfxConfigureCrop and \ref gfxConfigureResolution.
 u8* gfxGetFramebuffer(u32* width, u32* height);
 
diff --git a/nx/include/switch/display/nvgfx.h b/nx/include/switch/display/nvgfx.h
index 6d8a9f68..215f6f45 100644
--- a/nx/include/switch/display/nvgfx.h
+++ b/nx/include/switch/display/nvgfx.h
@@ -5,4 +5,4 @@ Result nvgfxInitialize(void);
 void nvgfxExit(void);
 Result nvgfxEventWait(u32 syncpt_id, u32 threshold, s32 timeout);
 Result nvgfxSubmitGpfifo(void);
-Result nvgfxGetFramebuffer(u8 **buffer, size_t *size);
+Result nvgfxGetFramebuffer(u8 **buffer, size_t *size, u32 *handle);
diff --git a/nx/include/switch/nvidia/address_space.h b/nx/include/switch/nvidia/address_space.h
index 49bfe2e2..1b3a8e5f 100644
--- a/nx/include/switch/nvidia/address_space.h
+++ b/nx/include/switch/nvidia/address_space.h
@@ -17,7 +17,7 @@ Result nvAddressSpaceReserveAlign(NvAddressSpace* a, NvPageSize align, u32 pages
 Result nvAddressSpaceReserveAtFixedAddr(NvAddressSpace* a, iova_t addr, u32 pages, NvPageSize page_sz);
 Result nvAddressSpaceReserveFull(NvAddressSpace* a);
 
-Result nvAddressSpaceMapBuffer(NvAddressSpace* a, NvBuffer* buffer, NvBufferKind kind, iova_t* iova_out);
+Result nvAddressSpaceMapBuffer(NvAddressSpace* a, u32 fd, NvBufferKind kind, iova_t* iova_out);
 
 struct NvChannel;
 Result nvAddressSpaceBindToChannel(NvAddressSpace* a, struct NvChannel* channel);
diff --git a/nx/source/display/gfx.c b/nx/source/display/gfx.c
index 0199701c..633d9c7a 100644
--- a/nx/source/display/gfx.c
+++ b/nx/source/display/gfx.c
@@ -26,6 +26,7 @@ static bool g_gfx_ProducerConnected = 0;
 static bool g_gfx_ProducerSlotsRequested[2] = {0, 0};
 static u8 *g_gfxFramebuf;
 static size_t g_gfxFramebufSize;
+static u32 g_gfxFramebufHandle;
 static BqFence g_gfx_DequeueBuffer_fence;
 static BqQueueBufferOutput g_gfx_Connect_QueueBufferOutput;
 static BqQueueBufferOutput g_gfx_QueueBuffer_QueueBufferOutput;
@@ -178,6 +179,7 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
     g_gfx_ProducerConnected = 0;
     g_gfxFramebuf = NULL;
     g_gfxFramebufSize = 0;
+    g_gfxFramebufHandle = 0;
     g_gfxMode = GfxMode_LinearDouble;
 
     g_gfx_drawflip = true;
@@ -249,7 +251,7 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
 
     if (R_SUCCEEDED(rc)) rc = nvgfxInitialize();
 
-    if (R_SUCCEEDED(rc)) rc = nvgfxGetFramebuffer(&g_gfxFramebuf, &g_gfxFramebufSize);
+    if (R_SUCCEEDED(rc)) rc = nvgfxGetFramebuffer(&g_gfxFramebuf, &g_gfxFramebufSize, &g_gfxFramebufHandle);
 
     if (R_SUCCEEDED(rc)) { //Official sw would use bqRequestBuffer() when required during swap-buffers/or similar, but that's not really an option here due to gfxSetDoubleBuffering().
        for(i=0; i<2; i++) {
@@ -312,6 +314,7 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
         g_gfx_ProducerConnected = 0;
         g_gfxFramebuf = NULL;
         g_gfxFramebufSize = 0;
+        g_gfxFramebufHandle = 0;
 
         g_gfx_framebuf_width = 0;
         g_gfx_framebuf_height = 0;
@@ -500,6 +503,11 @@ void gfxSwapBuffers(void) {
     if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadGfxDequeueBuffer));
 }
 
+u32 gfxGetFramebufferHandle(u32* offset) {
+    if (offset) *offset = g_gfxCurrentBuffer*g_gfx_singleframebuf_size;
+    return g_gfxFramebufHandle;
+}
+
 u8* gfxGetFramebuffer(u32* width, u32* height) {
     if(width) *width = g_gfx_framebuf_display_width;
     if(height) *height = g_gfx_framebuf_display_height;
@@ -556,4 +564,3 @@ void gfxFlushBuffers(void) {
 /*static Result _gfxGetDisplayResolution(u64 *width, u64 *height) {
     return viGetDisplayResolution(&g_gfxDisplay, width, height);
 }*/
-
diff --git a/nx/source/display/nvgfx.c b/nx/source/display/nvgfx.c
index 102859ae..6cdeb1e4 100644
--- a/nx/source/display/nvgfx.c
+++ b/nx/source/display/nvgfx.c
@@ -232,7 +232,7 @@ Result nvgfxEventWait(u32 syncpt_id, u32 threshold, s32 timeout)
     return rc;
 }
 
-Result nvgfxGetFramebuffer(u8 **buffer, size_t *size)
+Result nvgfxGetFramebuffer(u8 **buffer, size_t *size, u32 *handle)
 {
     if (!g_nvgfxInitialized)
         return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
@@ -241,7 +241,8 @@ Result nvgfxGetFramebuffer(u8 **buffer, size_t *size)
         *buffer = nvmap_objs[6].mem;
     if (size != NULL)
         *size = nvmap_objs[6].mem_size;
+    if (handle != NULL)
+        *handle = nvmap_objs[6].handle;
 
     return 0;
 }
-
diff --git a/nx/source/nvidia/address_space.c b/nx/source/nvidia/address_space.c
index f0724dd8..ad5cd2a2 100644
--- a/nx/source/nvidia/address_space.c
+++ b/nx/source/nvidia/address_space.c
@@ -47,10 +47,10 @@ Result nvAddressSpaceReserveFull(NvAddressSpace* a) {
 }
 
 Result nvAddressSpaceMapBuffer(
-        NvAddressSpace* a, NvBuffer* buffer, NvBufferKind kind,
+        NvAddressSpace* a, u32 fd, NvBufferKind kind,
         iova_t* iova_out) {
     return nvioctlNvhostAsGpu_MapBufferEx(
-        a->fd, NvMapBufferFlags_IsCachable, kind, buffer->fd, 0x10000, 0, 0, 0, iova_out);
+        a->fd, NvMapBufferFlags_IsCachable, kind, fd, 0x10000, 0, 0, 0, iova_out);
 }
 
 Result nvAddressSpaceBindToChannel(NvAddressSpace* a, NvChannel* channel) {
diff --git a/nx/source/nvidia/buffer.c b/nx/source/nvidia/buffer.c
index 4979aa72..d738dc52 100644
--- a/nx/source/nvidia/buffer.c
+++ b/nx/source/nvidia/buffer.c
@@ -71,7 +71,7 @@ static Result _nvBufferCreate(
             g_nvmap_fd, m->fd, 0, flags | NvBufferFlags_Nintendo, align, kind, m->cpu_addr);
 
     if (R_SUCCEEDED(rc))
-        rc = nvAddressSpaceMapBuffer(as, m, 0, &m->gpu_addr);
+        rc = nvAddressSpaceMapBuffer(as, m->fd, 0, &m->gpu_addr);
 
     if (R_FAILED(rc))
         nvBufferFree(m);
@@ -124,7 +124,7 @@ iova_t nvBufferGetGpuAddr(NvBuffer* m) {
 }
 
 Result nvBufferMapAsTexture(NvBuffer* m, NvBufferKind kind) {
-    return nvAddressSpaceMapBuffer(m->addr_space, m, kind, &m->gpu_addr_texture);
+    return nvAddressSpaceMapBuffer(m->addr_space, m->fd, kind, &m->gpu_addr_texture);
 }
 
 iova_t nvBufferGetGpuAddrTexture(NvBuffer* m) {