diff --git a/configure.ac b/configure.ac
index 217281f..ea485b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2361,6 +2361,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/drivers/radeon/Makefile
 		src/gallium/drivers/radeonsi/Makefile
 		src/gallium/drivers/rbug/Makefile
+		src/gallium/drivers/renderonly/Makefile
 		src/gallium/drivers/softpipe/Makefile
 		src/gallium/drivers/svga/Makefile
 		src/gallium/drivers/trace/Makefile
diff --git a/src/gallium/drivers/renderonly/Makefile.am b/src/gallium/drivers/renderonly/Makefile.am
new file mode 100644
index 0000000..ff9041b
--- /dev/null
+++ b/src/gallium/drivers/renderonly/Makefile.am
@@ -0,0 +1,11 @@
+include Makefile.sources
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CPPFLAGS = \
+	$(LIBDRM_CFLAGS) \
+	$(GALLIUM_CFLAGS)
+
+noinst_LTLIBRARIES = librenderonly.la
+
+librenderonly_la_SOURCES = \
+	$(C_SOURCES)
diff --git a/src/gallium/drivers/renderonly/Makefile.sources b/src/gallium/drivers/renderonly/Makefile.sources
new file mode 100644
index 0000000..6262a70
--- /dev/null
+++ b/src/gallium/drivers/renderonly/Makefile.sources
@@ -0,0 +1,4 @@
+C_SOURCES := \
+	renderonly_context.c \
+	renderonly_resource.c \
+	renderonly_screen.c
diff --git a/src/gallium/drivers/renderonly/renderonly_context.c b/src/gallium/drivers/renderonly/renderonly_context.c
new file mode 100644
index 0000000..d5e410e
--- /dev/null
+++ b/src/gallium/drivers/renderonly/renderonly_context.c
@@ -0,0 +1,721 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * 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 <stdlib.h>
+
+#include "util/u_debug.h"
+#include "util/u_inlines.h"
+
+#include "renderonly_context.h"
+#include "renderonly_resource.h"
+#include "renderonly_screen.h"
+
+static void
+renderonly_destroy(struct pipe_context *pcontext)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->destroy(context->gpu);
+	free(context);
+}
+
+static void
+renderonly_draw_vbo(struct pipe_context *pcontext,
+	       const struct pipe_draw_info *pinfo)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct pipe_draw_info info;
+
+	if (pinfo && pinfo->indirect) {
+		memcpy(&info, pinfo, sizeof(info));
+		info.indirect = renderonly_resource_unwrap(info.indirect);
+		pinfo = &info;
+	}
+
+	context->gpu->draw_vbo(context->gpu, pinfo);
+}
+
+static void *
+renderonly_create_blend_state(struct pipe_context *pcontext,
+			 const struct pipe_blend_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_blend_state(context->gpu, cso);
+}
+
+static void
+renderonly_bind_blend_state(struct pipe_context *pcontext,
+		       void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_blend_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_blend_state(struct pipe_context *pcontext,
+			 void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_blend_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_sampler_state(struct pipe_context *pcontext,
+			   const struct pipe_sampler_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_sampler_state(context->gpu, cso);
+}
+
+static void
+renderonly_bind_sampler_states(struct pipe_context *pcontext,
+			  unsigned shader,
+			  unsigned start_slot,
+			  unsigned num_samplers,
+			  void **samplers)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_sampler_states(context->gpu, shader, start_slot,
+					  num_samplers, samplers);
+}
+
+static void
+renderonly_delete_sampler_state(struct pipe_context *pcontext,
+			   void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_sampler_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_rasterizer_state(struct pipe_context *pcontext,
+			      const struct pipe_rasterizer_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_rasterizer_state(context->gpu, cso);
+}
+
+static void
+renderonly_bind_rasterizer_state(struct pipe_context *pcontext,
+			    void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_rasterizer_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_rasterizer_state(struct pipe_context *pcontext,
+			      void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_rasterizer_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_depth_stencil_alpha_state(struct pipe_context *pcontext,
+				       const struct pipe_depth_stencil_alpha_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_depth_stencil_alpha_state(context->gpu,
+							      cso);
+}
+
+static void
+renderonly_bind_depth_stencil_alpha_state(struct pipe_context *pcontext,
+				     void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_depth_stencil_alpha_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_depth_stencil_alpha_state(struct pipe_context *pcontext,
+				       void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_depth_stencil_alpha_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_fs_state(struct pipe_context *pcontext,
+		      const struct pipe_shader_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_fs_state(context->gpu, cso);
+}
+
+static void
+renderonly_bind_fs_state(struct pipe_context *pcontext,
+		    void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_fs_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_fs_state(struct pipe_context *pcontext,
+		      void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_fs_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_vs_state(struct pipe_context *pcontext,
+		      const struct pipe_shader_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_vs_state(context->gpu, cso);
+}
+
+static void
+renderonly_bind_vs_state(struct pipe_context *pcontext,
+		    void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_vs_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_vs_state(struct pipe_context *pcontext,
+		      void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_vs_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_gs_state(struct pipe_context *pcontext,
+		      const struct pipe_shader_state *cso)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_gs_state(context->gpu, cso);
+}
+
+static void
+renderonly_bind_gs_state(struct pipe_context *pcontext,
+		    void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_gs_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_gs_state(struct pipe_context *pcontext,
+		      void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_gs_state(context->gpu, so);
+}
+
+static void *
+renderonly_create_vertex_elements_state(struct pipe_context *pcontext,
+				   unsigned num_elements,
+				   const struct pipe_vertex_element *elements)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_vertex_elements_state(context->gpu,
+							  num_elements,
+							  elements);
+}
+
+static void
+renderonly_bind_vertex_elements_state(struct pipe_context *pcontext,
+				 void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->bind_vertex_elements_state(context->gpu, so);
+}
+
+static void
+renderonly_delete_vertex_elements_state(struct pipe_context *pcontext,
+				   void *so)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->delete_vertex_elements_state(context->gpu, so);
+}
+
+static void
+renderonly_set_constant_buffer(struct pipe_context *pcontext,
+			  uint shader,
+			  uint index,
+			  struct pipe_constant_buffer *buf)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct pipe_constant_buffer buffer;
+
+	if (buf && buf->buffer) {
+		memcpy(&buffer, buf, sizeof(buffer));
+		buffer.buffer = renderonly_resource_unwrap(buffer.buffer);
+		buf = &buffer;
+	}
+
+	context->gpu->set_constant_buffer(context->gpu, shader, index, buf);
+}
+
+static void
+renderonly_set_framebuffer_state(struct pipe_context *pcontext,
+			    const struct pipe_framebuffer_state *fb)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct pipe_framebuffer_state state;
+	unsigned i;
+
+	if (fb) {
+		memcpy(&state, fb, sizeof(state));
+
+		for (i = 0; i < fb->nr_cbufs; i++)
+			state.cbufs[i] = renderonly_surface_unwrap(fb->cbufs[i]);
+
+		while (i < PIPE_MAX_COLOR_BUFS)
+			state.cbufs[i++] = NULL;
+
+		state.zsbuf = renderonly_surface_unwrap(fb->zsbuf);
+
+		fb = &state;
+	}
+
+	context->gpu->set_framebuffer_state(context->gpu, fb);
+}
+
+static void
+renderonly_set_polygon_stipple(struct pipe_context *pcontext,
+			  const struct pipe_poly_stipple *stipple)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->set_polygon_stipple(context->gpu, stipple);
+}
+
+static void
+renderonly_set_scissor_states(struct pipe_context *pcontext,
+			 unsigned start_slot,
+			 unsigned num_scissors,
+			 const struct pipe_scissor_state *scissors)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->set_scissor_states(context->gpu, start_slot,
+					 num_scissors, scissors);
+}
+
+static void
+renderonly_set_viewport_states(struct pipe_context *pcontext,
+			  unsigned start_slot,
+			  unsigned num_viewports,
+			  const struct pipe_viewport_state *viewports)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->set_viewport_states(context->gpu, start_slot,
+					  num_viewports, viewports);
+}
+
+static void
+renderonly_set_sampler_views(struct pipe_context *pcontext,
+			unsigned shader,
+			unsigned start_slot,
+			unsigned num_views,
+			struct pipe_sampler_view **pviews)
+{
+	struct pipe_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	unsigned i;
+
+	for (i = 0; i < num_views; i++)
+		views[i] = renderonly_sampler_view_unwrap(pviews[i]);
+
+	context->gpu->set_sampler_views(context->gpu, shader, start_slot,
+					num_views, views);
+}
+
+static void
+renderonly_set_shader_images(struct pipe_context *pcontext,
+			   unsigned shader,
+			   unsigned start_slot, unsigned count,
+			   struct pipe_image_view **images)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->set_shader_images(context->gpu, shader, start_slot,
+					count, images);
+}
+
+static void
+renderonly_set_vertex_buffers(struct pipe_context *pcontext,
+			 unsigned start_slot,
+			 unsigned num_buffers,
+			 const struct pipe_vertex_buffer *buffers)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct pipe_vertex_buffer buf[PIPE_MAX_SHADER_INPUTS];
+	unsigned i;
+
+	if (num_buffers && buffers) {
+		memcpy(buf, buffers, num_buffers * sizeof(struct pipe_vertex_buffer));
+
+		for (i = 0; i < num_buffers; i++)
+			buf[i].buffer = renderonly_resource_unwrap(buf[i].buffer);
+
+		buffers = buf;
+	}
+
+	context->gpu->set_vertex_buffers(context->gpu, start_slot,
+					 num_buffers, buffers);
+}
+
+static void
+renderonly_set_index_buffer(struct pipe_context *pcontext,
+		       const struct pipe_index_buffer *buffer)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct pipe_index_buffer buf;
+
+	if (buffer) {
+		memcpy(&buf, buffer, sizeof(buf));
+		buf.buffer = renderonly_resource_unwrap(buf.buffer);
+		buffer = &buf;
+	}
+
+	context->gpu->set_index_buffer(context->gpu, buffer);
+}
+
+static struct pipe_stream_output_target *
+renderonly_create_stream_output_target(struct pipe_context *pcontext,
+				  struct pipe_resource *presource,
+				  unsigned buffer_offset,
+				  unsigned buffer_size)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	return context->gpu->create_stream_output_target(context->gpu,
+							 resource->gpu,
+							 buffer_offset,
+							 buffer_size);
+}
+
+static void
+renderonly_stream_output_target_destroy(struct pipe_context *pcontext,
+				   struct pipe_stream_output_target *target)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->stream_output_target_destroy(context->gpu, target);
+}
+
+static void
+renderonly_set_stream_output_targets(struct pipe_context *pcontext,
+				unsigned num_targets,
+				struct pipe_stream_output_target **targets,
+				const unsigned *offsets)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->set_stream_output_targets(context->gpu, num_targets,
+						targets, offsets);
+}
+
+static void
+renderonly_blit(struct pipe_context *pcontext,
+	   const struct pipe_blit_info *pinfo)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct pipe_blit_info info;
+
+	if (pinfo) {
+		memcpy(&info, pinfo, sizeof(info));
+		info.dst.resource = renderonly_resource_unwrap(info.dst.resource);
+		info.src.resource = renderonly_resource_unwrap(info.src.resource);
+		pinfo = &info;
+	}
+
+	context->gpu->blit(context->gpu, pinfo);
+}
+
+static void
+renderonly_clear(struct pipe_context *pcontext,
+	    unsigned buffers,
+	    const union pipe_color_union *color,
+	    double depth,
+	    unsigned stencil)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->clear(context->gpu, buffers, color, depth, stencil);
+}
+
+static void
+renderonly_flush(struct pipe_context *pcontext,
+	    struct pipe_fence_handle **fence,
+	    unsigned flags)
+{
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->flush(context->gpu, fence, flags);
+}
+
+static struct pipe_sampler_view *
+renderonly_create_sampler_view(struct pipe_context *pcontext,
+			  struct pipe_resource *ptexture,
+			  const struct pipe_sampler_view *template)
+{
+	struct renderonly_resource *texture = to_renderonly_resource(ptexture);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct renderonly_sampler_view *view;
+
+	view = calloc(1, sizeof(*view));
+	if (!view)
+		return NULL;
+
+	view->gpu = context->gpu->create_sampler_view(context->gpu,
+						      texture->gpu,
+						      template);
+	memcpy(&view->base, view->gpu, sizeof(*view->gpu));
+	/* overwrite to prevent reference from being released */
+	view->base.texture = NULL;
+
+	pipe_reference_init(&view->base.reference, 1);
+	pipe_resource_reference(&view->base.texture, ptexture);
+	view->base.context = pcontext;
+
+	return &view->base;
+}
+
+static void
+renderonly_sampler_view_destroy(struct pipe_context *pcontext,
+			   struct pipe_sampler_view *pview)
+{
+	struct renderonly_sampler_view *view = to_renderonly_sampler_view(pview);
+
+	pipe_resource_reference(&view->base.texture, NULL);
+	pipe_sampler_view_reference(&view->gpu, NULL);
+	free(view);
+}
+
+static void
+renderonly_flush_resource(struct pipe_context *pcontext,
+		     struct pipe_resource *presource)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct renderonly_screen *screen = to_renderonly_screen(presource->screen);
+	struct pipe_blit_info blit;
+
+	context->gpu->flush_resource(context->gpu, resource->gpu);
+
+	if (!resource->scanout || !screen->ops->intermediate_rendering)
+		return;
+
+	/* we need to blit our gpu render result to dumb buffer */
+	memset(&blit, 0, sizeof(blit));
+	blit.mask = PIPE_MASK_RGBA;
+	blit.filter = PIPE_TEX_FILTER_LINEAR;
+	blit.src.resource = resource->gpu;
+	blit.src.format = resource->gpu->format;
+	blit.src.level = 0;
+	blit.src.box.width = resource->gpu->width0;
+	blit.src.box.height = resource->gpu->height0;
+	blit.dst.resource = resource->prime;
+	blit.dst.format = resource->prime->format;
+	blit.dst.level = 0;
+	blit.dst.box.width = resource->prime->width0;
+	blit.dst.box.height = resource->prime->height0;
+
+	context->gpu->blit(context->gpu, &blit);
+}
+
+static void *
+renderonly_transfer_map(struct pipe_context *pcontext,
+		   struct pipe_resource *presource,
+		   unsigned level,
+		   unsigned usage,
+		   const struct pipe_box *box,
+		   struct pipe_transfer **ptransfer)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct renderonly_transfer *transfer;
+
+	transfer = calloc(1, sizeof(*transfer));
+	if (!transfer)
+		return NULL;
+
+	transfer->map = context->gpu->transfer_map(context->gpu,
+						   resource->gpu,
+						   level,
+						   usage,
+						   box,
+						   &transfer->gpu);
+	memcpy(&transfer->base, transfer->gpu, sizeof(*transfer->gpu));
+	transfer->base.resource = NULL;
+	pipe_resource_reference(&transfer->base.resource, presource);
+
+	*ptransfer = &transfer->base;
+
+	return transfer->map;
+}
+
+static void
+renderonly_transfer_unmap(struct pipe_context *pcontext,
+		     struct pipe_transfer *ptransfer)
+{
+	struct renderonly_transfer *transfer = to_renderonly_transfer(ptransfer);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->transfer_unmap(context->gpu, transfer->gpu);
+	pipe_resource_reference(&transfer->base.resource, NULL);
+	free(transfer);
+}
+
+static void
+renderonly_transfer_inline_write(struct pipe_context *pcontext,
+			    struct pipe_resource *presource,
+			    unsigned level,
+			    unsigned usage,
+			    const struct pipe_box *box,
+			    const void *data,
+			    unsigned stride,
+			    unsigned layer_stride)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+
+	context->gpu->transfer_inline_write(context->gpu, resource->gpu,
+					    level, usage, box, data, stride,
+					    layer_stride);
+}
+
+struct pipe_context *
+renderonly_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+	struct renderonly_context *context;
+
+	context = calloc(1, sizeof(*context));
+	if (!context)
+		return NULL;
+
+	context->gpu = screen->gpu->context_create(screen->gpu, priv, flags);
+	if (!context->gpu) {
+		debug_error("failed to create GPU context\n");
+		free(context);
+		return NULL;
+	}
+
+	context->base.screen = &screen->base;
+	context->base.priv = priv;
+
+	context->base.destroy = renderonly_destroy;
+
+	context->base.draw_vbo = renderonly_draw_vbo;
+
+	context->base.create_blend_state = renderonly_create_blend_state;
+	context->base.bind_blend_state = renderonly_bind_blend_state;
+	context->base.delete_blend_state = renderonly_delete_blend_state;
+
+	context->base.create_sampler_state = renderonly_create_sampler_state;
+	context->base.bind_sampler_states = renderonly_bind_sampler_states;
+	context->base.delete_sampler_state = renderonly_delete_sampler_state;
+
+	context->base.create_rasterizer_state = renderonly_create_rasterizer_state;
+	context->base.bind_rasterizer_state = renderonly_bind_rasterizer_state;
+	context->base.delete_rasterizer_state = renderonly_delete_rasterizer_state;
+
+	context->base.create_depth_stencil_alpha_state = renderonly_create_depth_stencil_alpha_state;
+	context->base.bind_depth_stencil_alpha_state = renderonly_bind_depth_stencil_alpha_state;
+	context->base.delete_depth_stencil_alpha_state = renderonly_delete_depth_stencil_alpha_state;
+
+	context->base.create_fs_state = renderonly_create_fs_state;
+	context->base.bind_fs_state = renderonly_bind_fs_state;
+	context->base.delete_fs_state = renderonly_delete_fs_state;
+
+	context->base.create_vs_state = renderonly_create_vs_state;
+	context->base.bind_vs_state = renderonly_bind_vs_state;
+	context->base.delete_vs_state = renderonly_delete_vs_state;
+
+	context->base.create_gs_state = renderonly_create_gs_state;
+	context->base.bind_gs_state = renderonly_bind_gs_state;
+	context->base.delete_gs_state = renderonly_delete_gs_state;
+
+	context->base.create_vertex_elements_state = renderonly_create_vertex_elements_state;
+	context->base.bind_vertex_elements_state = renderonly_bind_vertex_elements_state;
+	context->base.delete_vertex_elements_state = renderonly_delete_vertex_elements_state;
+
+	context->base.set_constant_buffer = renderonly_set_constant_buffer;
+	context->base.set_framebuffer_state = renderonly_set_framebuffer_state;
+	context->base.set_polygon_stipple = renderonly_set_polygon_stipple;
+	context->base.set_scissor_states = renderonly_set_scissor_states;
+	context->base.set_viewport_states = renderonly_set_viewport_states;
+	context->base.set_sampler_views = renderonly_set_sampler_views;
+
+	context->base.set_shader_images = renderonly_set_shader_images;
+	context->base.set_vertex_buffers = renderonly_set_vertex_buffers;
+	context->base.set_index_buffer = renderonly_set_index_buffer;
+
+	context->base.create_stream_output_target = renderonly_create_stream_output_target;
+	context->base.stream_output_target_destroy = renderonly_stream_output_target_destroy;
+	context->base.set_stream_output_targets = renderonly_set_stream_output_targets;
+
+	context->base.blit = renderonly_blit;
+	context->base.clear = renderonly_clear;
+	context->base.flush = renderonly_flush;
+
+	context->base.create_sampler_view = renderonly_create_sampler_view;
+	context->base.sampler_view_destroy = renderonly_sampler_view_destroy;
+
+	context->base.flush_resource = renderonly_flush_resource;
+
+	context->base.create_surface = renderonly_create_surface;
+	context->base.surface_destroy = renderonly_surface_destroy;
+
+	context->base.transfer_map = renderonly_transfer_map;
+	context->base.transfer_unmap = renderonly_transfer_unmap;
+	context->base.transfer_inline_write = renderonly_transfer_inline_write;
+
+	return &context->base;
+}
diff --git a/src/gallium/drivers/renderonly/renderonly_context.h b/src/gallium/drivers/renderonly/renderonly_context.h
new file mode 100644
index 0000000..f780e69
--- /dev/null
+++ b/src/gallium/drivers/renderonly/renderonly_context.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * 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 RENDERONLY_CONTEXT_H
+#define RENDERONLY_CONTEXT_H
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+struct renderonly_screen;
+
+struct renderonly_context {
+	struct pipe_context base;
+	struct pipe_context *gpu;
+};
+
+static inline struct renderonly_context *
+to_renderonly_context(struct pipe_context *context)
+{
+	return (struct renderonly_context *)context;
+}
+
+struct pipe_context *renderonly_context_create(struct pipe_screen *pscreen,
+					  void *priv, unsigned flags);
+
+struct renderonly_sampler_view {
+	struct pipe_sampler_view base;
+	struct pipe_sampler_view *gpu;
+};
+
+static inline struct renderonly_sampler_view *
+to_renderonly_sampler_view(struct pipe_sampler_view *view)
+{
+	return (struct renderonly_sampler_view *)view;
+}
+
+static inline struct pipe_sampler_view *
+renderonly_sampler_view_unwrap(struct pipe_sampler_view *view)
+{
+	if (!view)
+		return NULL;
+
+	return to_renderonly_sampler_view(view)->gpu;
+}
+
+struct renderonly_transfer {
+	struct pipe_transfer base;
+	struct pipe_transfer *gpu;
+
+	unsigned int count;
+	void *map;
+};
+
+static inline struct renderonly_transfer *
+to_renderonly_transfer(struct pipe_transfer *transfer)
+{
+	return (struct renderonly_transfer *)transfer;
+}
+
+#endif /* RENDERONLY_CONTEXT_H */
diff --git a/src/gallium/drivers/renderonly/renderonly_resource.c b/src/gallium/drivers/renderonly/renderonly_resource.c
new file mode 100644
index 0000000..b9d78ac
--- /dev/null
+++ b/src/gallium/drivers/renderonly/renderonly_resource.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <xf86drm.h>
+
+#include "pipe/p_state.h"
+#include "util/u_debug.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include "renderonly_context.h"
+#include "renderonly_resource.h"
+#include "renderonly_screen.h"
+
+static bool resource_import_scanout(struct renderonly_screen *screen,
+		     struct renderonly_resource *resource,
+		     const struct pipe_resource *template)
+{
+	struct winsys_handle handle;
+	boolean status;
+	int fd, err;
+
+	resource->gpu = screen->gpu->resource_create(screen->gpu,
+							     template);
+	if (!resource->gpu)
+		return false;
+
+	memset(&handle, 0, sizeof(handle));
+	handle.type = DRM_API_HANDLE_TYPE_FD;
+
+	status = screen->gpu->resource_get_handle(screen->gpu,
+							  resource->gpu,
+							  &handle);
+	if (!status)
+		return false;
+
+	resource->stride = handle.stride;
+	fd = handle.handle;
+
+	err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
+	if (err < 0) {
+		fprintf(stderr, "drmPrimeFDToHandle() failed: %s\n",
+			strerror(errno));
+		close(fd);
+		return false;
+	}
+
+	close(fd);
+
+	if (screen->ops->tiling) {
+		err = screen->ops->tiling(screen->fd, resource->handle);
+		if (err < 0) {
+			fprintf(stderr, "failed to set tiling parameters: %s\n",
+				strerror(errno));
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static bool resource_dumb(struct renderonly_screen *screen,
+		     struct renderonly_resource *resource,
+		     const struct pipe_resource *template)
+{
+	struct drm_mode_create_dumb create_dumb = { 0 };
+	struct winsys_handle handle;
+	int prime_fd, err;
+
+	/* create dumb buffer at scanout GPU */
+	create_dumb.width = template->width0;
+	create_dumb.height = template->height0;
+	create_dumb.bpp = 32;
+	create_dumb.flags = 0;
+	create_dumb.pitch = 0;
+	create_dumb.size = 0;
+	create_dumb.handle = 0;
+
+	err = ioctl(screen->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
+	if (err < 0) {
+		fprintf(stderr, "DRM_IOCTL_MODE_CREATE_DUMB failed: %s\n",
+			strerror(errno));
+		return false;
+	}
+
+	resource->handle = create_dumb.handle;
+	resource->stride = create_dumb.pitch;
+
+	/* create resource at renderonly GPU */
+	resource->gpu = screen->gpu->resource_create(screen->gpu, template);
+	if (!resource->gpu)
+		return false;
+
+	/* export dumb buffer */
+	err = drmPrimeHandleToFD(screen->fd, create_dumb.handle, O_CLOEXEC, &prime_fd);
+	if (err < 0) {
+		fprintf(stderr, "failed to export dumb buffer: %s\n",
+			strerror(errno));
+		return false;
+	}
+
+	/* import dumb buffer */
+	handle.type = DRM_API_HANDLE_TYPE_FD;
+	handle.handle = prime_fd;
+	handle.stride = create_dumb.pitch;
+
+	resource->prime = screen->gpu->resource_from_handle(screen->gpu, template, &handle);
+	if (!resource->prime) {
+		fprintf(stderr, "failed to create resource_from_handle: %s\n",
+			strerror(errno));
+		return false;
+	}
+
+	return true;
+}
+
+struct pipe_resource *
+renderonly_resource_create(struct pipe_screen *pscreen,
+		      const struct pipe_resource *template)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+	struct renderonly_resource *resource;
+
+	resource = calloc(1, sizeof(*resource));
+	if (!resource)
+		return NULL;
+
+	if (template->bind & PIPE_BIND_SCANOUT) {
+
+		bool success = false;
+
+		if (!screen->ops->intermediate_rendering) {
+			/* create scanout resource in renderonly GPU, export it
+			 * and import it into the scanout hardware. If defined
+			 * tiling will be setup for the crated resource. */
+			success = resource_import_scanout(screen, resource, template);
+		} else {
+			/* create dump buffer in scanout hardware, export it
+			 * and import it into renderonly GPU. */
+			success = resource_dumb(screen, resource, template);
+		}
+
+		if (!success)
+			goto destroy;
+
+		resource->scanout = true;
+
+	} else {
+		resource->gpu = screen->gpu->resource_create(screen->gpu,
+							     template);
+		if (!resource->gpu)
+			goto destroy;
+	}
+
+	memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
+	pipe_reference_init(&resource->base.reference, 1);
+	resource->base.screen = &screen->base;
+
+	return &resource->base;
+
+destroy:
+	if (resource->gpu)
+		screen->gpu->resource_destroy(screen->gpu, resource->gpu);
+	free(resource);
+	return NULL;
+}
+
+struct pipe_resource *
+renderonly_resource_from_handle(struct pipe_screen *pscreen,
+			   const struct pipe_resource *template,
+			   struct winsys_handle *handle)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+	struct renderonly_resource *resource;
+
+	resource = calloc(1, sizeof(*resource));
+	if (!resource)
+		return NULL;
+
+	resource->gpu = screen->gpu->resource_from_handle(screen->gpu,
+							  template,
+							  handle);
+	if (!resource->gpu) {
+		free(resource);
+		return NULL;
+	}
+
+	memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
+	pipe_reference_init(&resource->base.reference, 1);
+	resource->base.screen = &screen->base;
+
+	return &resource->base;
+}
+
+boolean
+renderonly_resource_get_handle(struct pipe_screen *pscreen,
+			  struct pipe_resource *presource,
+			  struct winsys_handle *handle)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+	boolean ret = TRUE;
+
+	if (presource->bind & PIPE_BIND_SCANOUT) {
+		handle->handle = resource->handle;
+		handle->stride = resource->stride;
+	} else {
+		ret = screen->gpu->resource_get_handle(screen->gpu,
+						       resource->gpu,
+						       handle);
+	}
+
+	return ret;
+}
+
+void
+renderonly_resource_destroy(struct pipe_screen *pscreen,
+		       struct pipe_resource *presource)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+
+	pipe_resource_reference(&resource->gpu, NULL);
+	free(resource);
+}
+
+struct pipe_surface *
+renderonly_create_surface(struct pipe_context *pcontext,
+		     struct pipe_resource *presource,
+		     const struct pipe_surface *template)
+{
+	struct renderonly_resource *resource = to_renderonly_resource(presource);
+	struct renderonly_context *context = to_renderonly_context(pcontext);
+	struct renderonly_surface *surface;
+
+	surface = calloc(1, sizeof(*surface));
+	if (!surface)
+		return NULL;
+
+	surface->gpu = context->gpu->create_surface(context->gpu,
+						    resource->gpu,
+						    template);
+	if (!surface->gpu) {
+		free(surface);
+		return NULL;
+	}
+
+	memcpy(&surface->base, surface->gpu, sizeof(*surface->gpu));
+	/* overwrite to prevent reference from being released */
+	surface->base.texture = NULL;
+
+	pipe_reference_init(&surface->base.reference, 1);
+	pipe_resource_reference(&surface->base.texture, presource);
+	surface->base.context = &context->base;
+
+	return &surface->base;
+}
+
+void
+renderonly_surface_destroy(struct pipe_context *pcontext,
+		      struct pipe_surface *psurface)
+{
+	struct renderonly_surface *surface = to_renderonly_surface(psurface);
+
+	pipe_resource_reference(&surface->base.texture, NULL);
+	pipe_surface_reference(&surface->gpu, NULL);
+	free(surface);
+}
diff --git a/src/gallium/drivers/renderonly/renderonly_resource.h b/src/gallium/drivers/renderonly/renderonly_resource.h
new file mode 100644
index 0000000..309831b
--- /dev/null
+++ b/src/gallium/drivers/renderonly/renderonly_resource.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * 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 RENDERONLY_RESOURCE_H
+#define RENDERONLY_RESOURCE_H
+
+#include "pipe/p_state.h"
+
+struct winsys_handle;
+
+struct renderonly_resource {
+	struct pipe_resource base;
+	struct pipe_resource *gpu;
+
+	bool scanout;
+	struct pipe_resource *prime;
+
+	uint32_t stride;
+	uint32_t handle;
+	size_t size;
+};
+
+static inline struct renderonly_resource *
+to_renderonly_resource(struct pipe_resource *resource)
+{
+	return (struct renderonly_resource *)resource;
+}
+
+static inline struct pipe_resource *
+renderonly_resource_unwrap(struct pipe_resource *resource)
+{
+	if (!resource)
+		return NULL;
+
+	return to_renderonly_resource(resource)->gpu;
+}
+
+struct pipe_resource *
+renderonly_resource_create(struct pipe_screen *pscreen,
+		      const struct pipe_resource *template);
+struct pipe_resource *
+renderonly_resource_from_handle(struct pipe_screen *pscreen,
+			   const struct pipe_resource *template,
+			   struct winsys_handle *handle);
+boolean
+renderonly_resource_get_handle(struct pipe_screen *pscreen,
+			  struct pipe_resource *resource,
+			  struct winsys_handle *handle);
+void
+renderonly_resource_destroy(struct pipe_screen *pscreen,
+		       struct pipe_resource *resource);
+
+struct renderonly_surface {
+	struct pipe_surface base;
+	struct pipe_surface *gpu;
+};
+
+static inline struct renderonly_surface *
+to_renderonly_surface(struct pipe_surface *surface)
+{
+	return (struct renderonly_surface *)surface;
+}
+
+static inline struct pipe_surface *
+renderonly_surface_unwrap(struct pipe_surface *surface)
+{
+	if (!surface)
+		return NULL;
+
+	return to_renderonly_surface(surface)->gpu;
+}
+
+struct pipe_surface *
+renderonly_create_surface(struct pipe_context *pcontext,
+		     struct pipe_resource *presource,
+		     const struct pipe_surface *template);
+void
+renderonly_surface_destroy(struct pipe_context *pcontext,
+		      struct pipe_surface *psurface);
+
+#endif /* RENDERONLY_RESOURCE_H */
diff --git a/src/gallium/drivers/renderonly/renderonly_screen.c b/src/gallium/drivers/renderonly/renderonly_screen.c
new file mode 100644
index 0000000..965b358
--- /dev/null
+++ b/src/gallium/drivers/renderonly/renderonly_screen.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <xf86drm.h>
+
+#include "util/u_string.h"
+#include "util/u_debug.h"
+
+#include "renderonly_context.h"
+#include "renderonly_resource.h"
+#include "renderonly_screen.h"
+
+static const char *
+renderonly_get_name(struct pipe_screen *pscreen)
+{
+	static char buffer[256];
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	util_snprintf(buffer, sizeof(buffer), "%s-%s",
+			drmGetDeviceNameFromFd(screen->fd),
+			screen->gpu->get_name(screen->gpu));
+	return buffer;
+}
+
+static const char *
+renderonly_get_vendor(struct pipe_screen *pscreen)
+{
+	return "renderonly";
+}
+
+static void renderonly_screen_destroy(struct pipe_screen *pscreen)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	screen->gpu->destroy(screen->gpu);
+	free(pscreen);
+}
+
+static int
+renderonly_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	return screen->gpu->get_param(screen->gpu, param);
+}
+
+static float
+renderonly_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	return screen->gpu->get_paramf(screen->gpu, param);
+}
+
+static int
+renderonly_screen_get_shader_param(struct pipe_screen *pscreen,
+			      unsigned shader,
+			      enum pipe_shader_cap param)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	return screen->gpu->get_shader_param(screen->gpu, shader, param);
+}
+
+static boolean
+renderonly_screen_is_format_supported(struct pipe_screen *pscreen,
+				 enum pipe_format format,
+				 enum pipe_texture_target target,
+				 unsigned sample_count,
+				 unsigned usage)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	return screen->gpu->is_format_supported(screen->gpu, format, target,
+						sample_count, usage);
+}
+
+static void
+renderonly_fence_reference(struct pipe_screen *pscreen,
+		      struct pipe_fence_handle **ptr,
+		      struct pipe_fence_handle *fence)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	screen->gpu->fence_reference(screen->gpu, ptr, fence);
+}
+
+static boolean
+renderonly_fence_finish(struct pipe_screen *pscreen,
+		   struct pipe_fence_handle *fence,
+		   uint64_t timeout)
+{
+	struct renderonly_screen *screen = to_renderonly_screen(pscreen);
+
+	return screen->gpu->fence_finish(screen->gpu, fence, timeout);
+}
+
+static int renderonly_open_render_node(int fd)
+{
+	return open("/dev/dri/renderD128", O_RDWR);
+}
+
+struct pipe_screen *
+renderonly_screen_create(int fd, const struct renderonly_ops *ops)
+{
+	struct renderonly_screen *screen;
+
+	screen = calloc(1, sizeof(*screen));
+	if (!screen)
+		return NULL;
+
+	screen->fd = fd;
+	screen->ops = ops;
+	assert(screen->ops);
+
+	screen->gpu_fd = renderonly_open_render_node(screen->fd);
+	if (screen->gpu_fd < 0) {
+		fprintf(stderr, "failed to open GPU device: %s\n",
+			strerror(errno));
+		free(screen);
+		return NULL;
+	}
+
+	assert(screen->ops->open);
+	screen->gpu = screen->ops->open(screen->gpu_fd);
+	if (!screen->gpu) {
+		fprintf(stderr, "failed to create GPU screen\n");
+		close(screen->gpu_fd);
+		free(screen);
+		return NULL;
+	}
+
+	screen->base.get_name = renderonly_get_name;
+	screen->base.get_vendor = renderonly_get_vendor;
+	screen->base.destroy = renderonly_screen_destroy;
+	screen->base.get_param = renderonly_screen_get_param;
+	screen->base.get_paramf = renderonly_screen_get_paramf;
+	screen->base.get_shader_param = renderonly_screen_get_shader_param;
+	screen->base.context_create = renderonly_context_create;
+	screen->base.is_format_supported = renderonly_screen_is_format_supported;
+
+	screen->base.resource_create = renderonly_resource_create;
+	screen->base.resource_from_handle = renderonly_resource_from_handle;
+	screen->base.resource_get_handle = renderonly_resource_get_handle;
+	screen->base.resource_destroy = renderonly_resource_destroy;
+
+	screen->base.fence_reference = renderonly_fence_reference;
+	screen->base.fence_finish = renderonly_fence_finish;
+
+	if (ops->intermediate_rendering)
+		screen->base.flush_frontbuffer = NULL; /* TODO */
+
+	return &screen->base;
+}
diff --git a/src/gallium/drivers/renderonly/renderonly_screen.h b/src/gallium/drivers/renderonly/renderonly_screen.h
new file mode 100644
index 0000000..cf35671
--- /dev/null
+++ b/src/gallium/drivers/renderonly/renderonly_screen.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * 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 RENDERONLY_SCREEN_H
+#define RENDERONLY_SCREEN_H
+
+#include "pipe/p_screen.h"
+
+struct renderonly_ops {
+	struct pipe_screen *(*open)(int fd);
+	int (*tiling)(int fd, uint32_t handle);
+
+	bool intermediate_rendering;
+};
+
+struct renderonly_screen {
+	struct pipe_screen base;
+	int fd;
+
+	struct pipe_screen *gpu;
+	int gpu_fd;
+
+	const struct renderonly_ops *ops;
+};
+
+static inline struct renderonly_screen *
+to_renderonly_screen(struct pipe_screen *pscreen)
+{
+   return (struct renderonly_screen *)pscreen;
+}
+
+struct pipe_screen *renderonly_screen_create(int fd,
+	const struct renderonly_ops *ops);
+
+#endif /* RENDERONLY_SCREEN_H */
