Commits

Michael Ludwig  committed acfdd97

Add DestructibleManager, update AbstractFramework to FrameworkImpl, remove ResourceManager and ResourceDriver, and move that logic into a clean hierarchy of builders for each resource type.

  • Participants
  • Parent commits 892899b

Comments (0)

Files changed (32)

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractFixedFunctionRenderer.java

 import com.ferox.math.Matrix4;
 import com.ferox.math.Vector3;
 import com.ferox.math.Vector4;
-import com.ferox.renderer.ContextState;
-import com.ferox.renderer.FixedFunctionRenderer;
-import com.ferox.renderer.RenderCapabilities;
-import com.ferox.renderer.Renderer;
+import com.ferox.renderer.*;
+import com.ferox.renderer.geom.VertexBufferObject;
 import com.ferox.renderer.impl.FixedFunctionState.*;
 import com.ferox.renderer.impl.drivers.TextureHandle;
 import com.ferox.renderer.impl.drivers.VertexBufferObjectHandle;
-import com.ferox.resource.BufferData.DataType;
-import com.ferox.resource.Texture;
-import com.ferox.resource.Texture.Target;
-import com.ferox.resource.VertexAttribute;
-import com.ferox.resource.VertexBufferObject;
+import com.ferox.renderer.texture.Texture.Target;
 
 /**
  * <p/>
 
         if (state == null) {
             // init state
-            RenderCapabilities caps = surface.getFramework().getCapabilities();
+            Capabilities caps = surface.getFramework().getCapabilities();
             state = new FixedFunctionState(caps.getMaxActiveLights(),
                                            caps.getMaxFixedPipelineTextures(),
                                            caps.getMaxTextureCoordinates());

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractFramework.java

-/*
- * Ferox, a graphics and game library in Java
- *
- * Copyright (c) 2012, Michael Ludwig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *     Redistributions of source code must retain the above copyright notice,
- *         this list of conditions and the following disclaimer.
- *     Redistributions in binary form must reproduce the above copyright notice,
- *         this list of conditions and the following disclaimer in the
- *         documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.ferox.renderer.impl;
-
-import com.ferox.renderer.*;
-import com.ferox.resource.Resource;
-import com.ferox.resource.Resource.Status;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.*;
-
-/**
- * AbstractFramework is an implementation of Framework that delegates all OpenGL specific
- * operations to a {@link ResourceManager}, {@link ContextManager} and {@link
- * SurfaceFactory}. Concrete implementations must provide {@link ResourceDriver
- * ResourceDrivers} for a ResourceManager and an implementation of SurfaceFactory. It is
- * recommended that they also provide a static method to create fully functioning
- * framework that calls {@link #initialize()} before passing the framework to application
- * code.
- *
- * @author Michael Ludwig
- */
-public abstract class AbstractFramework implements Framework {
-    /**
-     * The name of the task group used for the convenience functions update() and
-     * dispose() and other internal resource related tasks.
-     */
-    public static final String DEFAULT_RESOURCE_TASK_GROUP = "resource";
-
-    private final CopyOnWriteArraySet<AbstractSurface> surfaces;
-
-    private final SurfaceFactory surfaceFactory;
-
-    private RenderCapabilities renderCaps; // final after initialize() has been called.
-
-    private final LifeCycleManager lifecycleManager;
-    private final ResourceManager resourceManager;
-    private final ContextManager contextManager;
-
-    // fullscreen support
-    private final Object fullscreenLock;
-    private OnscreenSurface fullscreenSurface;
-
-    /**
-     * <p/>
-     * Create a new AbstractFramework. The parameter, <var>numThreads</var> defines the
-     * number of threads that the framework's ContextManager will use. This constructor
-     * will also create an offscreen context that will later be shared with all created
-     * surfaces for this framework. The given SurfaceFactory is used to create surfaces
-     * for the Framework. The list of drivers are given directly to a {@link
-     * ResourceManager}.
-     * <p/>
-     * After constructing an AbstractFramework, {@link #initialize()} must be invoked
-     * before it can be used.
-     *
-     * @param surfaceFactory The SurfaceFactory used to create surfaces
-     * @param numThreads     The number of internal threads this framework's
-     *                       ContextManager will use
-     * @param drivers        A varargs array of ResourceDrivers that handle the low-level
-     *                       graphics work for resources
-     *
-     * @throws NullPointerException if surfaceFactory or any driver is null
-     */
-    public AbstractFramework(SurfaceFactory surfaceFactory, ResourceDriver... drivers) {
-        if (surfaceFactory == null) {
-            throw new NullPointerException("SurfaceFactory cannot be null");
-        }
-
-        this.surfaceFactory = surfaceFactory;
-
-        contextManager = new ContextManager();
-        resourceManager = new ResourceManager(contextManager, drivers);
-
-        surfaces = new CopyOnWriteArraySet<AbstractSurface>();
-        lifecycleManager = new LifeCycleManager("ferox-renderer");
-
-        fullscreenLock = new Object();
-        fullscreenSurface = null;
-    }
-
-    /**
-     * Complete the initialization of the framework so that the public interface defined
-     * in {@link Framework} is usable. It is recommended that concrete implementations of
-     * AbstractFramework define a static method that creates the framework and invokes
-     * this method.
-     */
-    public void initialize() {
-        lifecycleManager.start(new Runnable() {
-            @Override
-            public void run() {
-                // Start up the context manager and resource manager
-                contextManager.initialize(lifecycleManager, surfaceFactory);
-                resourceManager.initialize(lifecycleManager);
-
-                // Fetch the RenderCapabilities now, we do it this way to improve
-                // the Framework creation time instead of forcing OpenGL wrappers to
-                // create and discard a context solely for capabilities detection.
-                Future<RenderCapabilities> caps = contextManager
-                        .invokeOnContextThread(new Callable<RenderCapabilities>() {
-                            @Override
-                            public RenderCapabilities call() throws Exception {
-                                OpenGLContext context = contextManager.ensureContext();
-                                return context.getRenderCapabilities();
-                            }
-                        }, false);
-
-                renderCaps = getFuture(caps);
-            }
-        });
-    }
-
-    @Override
-    public OnscreenSurface createSurface(final OnscreenSurfaceOptions options) {
-        if (options == null) {
-            throw new NullPointerException("Options cannot be null");
-        }
-
-        // This task is not accepted during shutdown
-        Future<OnscreenSurface> create = contextManager
-                .invokeOnContextThread(new Callable<OnscreenSurface>() {
-                    @Override
-                    public OnscreenSurface call() throws Exception {
-                        synchronized (fullscreenLock) {
-                            if (options.getFullscreenMode() != null &&
-                                fullscreenSurface != null) {
-                                throw new SurfaceCreationException(
-                                        "Cannot create fullscreen surface when an existing surface is fullscreen");
-                            }
-
-                            AbstractOnscreenSurface created = surfaceFactory
-                                    .createOnscreenSurface(AbstractFramework.this,
-                                                           options, contextManager
-                                            .getSharedContext());
-                            surfaces.add(created);
-                            if (created.getOptions().getFullscreenMode() != null) {
-                                fullscreenSurface = created;
-                            }
-
-                            contextManager.setActiveSurface(created, 0);
-                            return created;
-                        }
-                    }
-                }, false);
-        return getFuture(create);
-    }
-
-    @Override
-    public TextureSurface createSurface(final TextureSurfaceOptions options) {
-        if (options == null) {
-            throw new NullPointerException("Options cannot be null");
-        }
-
-        // This task is not accepted during shutdown
-        Future<TextureSurface> create = contextManager
-                .invokeOnContextThread(new Callable<TextureSurface>() {
-                    @Override
-                    public TextureSurface call() throws Exception {
-                        AbstractTextureSurface created = surfaceFactory
-                                .createTextureSurface(AbstractFramework.this, options,
-                                                      contextManager.getSharedContext());
-                        surfaces.add(created);
-
-                        // Mark all textures as non-disposable
-                        if (created.getDepthBuffer() != null) {
-                            resourceManager
-                                    .setDisposable(created.getDepthBuffer(), false);
-                        }
-                        for (int i = 0; i < created.getNumColorBuffers(); i++) {
-                            resourceManager
-                                    .setDisposable(created.getColorBuffer(i), false);
-                        }
-
-                        contextManager.setActiveSurface(created, 0);
-                        return created;
-                    }
-                }, false);
-
-        return getFuture(create);
-    }
-
-    @Override
-    public void destroy() {
-        final List<Exception> surfaceDestroyExceptions = new ArrayList<Exception>();
-        lifecycleManager.stop(new Runnable() {
-                                  @Override
-                                  public void run() {
-                                      // Destroy all remaining surfaces
-                                      // The loop is structured this way so that we don't get an
-                                      // iterator snapshot that's not updated if there were any
-                                      // pending creates before we transitioned to STOPPING
-                                      while (!surfaces.isEmpty()) {
-                                          AbstractSurface toDestroy = surfaces.iterator()
-                                                                              .next();
-                                          try {
-                                              toDestroy.destroy().get();
-                                          } catch (Exception e) {
-                                              // accumulate the exceptions but continue to destroy
-                                              // all of the surfaces
-                                              surfaceDestroyExceptions.add(e);
-                                              // must remove this surface so the loop can terminate
-                                              surfaces.remove(toDestroy);
-                                          }
-                                      }
-                                  }
-                              }, new Runnable() {
-                                  @Override
-                                  public void run() {
-                                      // Don't destroy native surface resources until the very end
-                                      surfaceFactory.destroy();
-                                  }
-                              }
-                             );
-
-        if (!surfaceDestroyExceptions.isEmpty()) {
-            throw new FrameworkException(surfaceDestroyExceptions.size() +
-                                         " exception(s) while destroying surface, first failure:",
-                                         surfaceDestroyExceptions.get(0));
-        }
-    }
-
-    @Override
-    public boolean isDestroyed() {
-        return lifecycleManager.isStopped();
-    }
-
-    @Override
-    public <T> Future<T> queue(Task<T> task) {
-        // Specify false so that these tasks are only queued while the
-        // state is ACTIVE
-        return contextManager.invokeOnContextThread(new TaskCallable<T>(task), false);
-    }
-
-    @Override
-    public Status update(Resource resource) {
-        return getFuture(queue(new UpdateResourceTask(resource)));
-    }
-
-    @Override
-    public void dispose(Resource resource) {
-        getFuture(queue(new DisposeResourceTask(resource)));
-    }
-
-    @Override
-    public Future<Void> flush(Surface surface) {
-        return queue(new FlushSurfaceTask(surface));
-    }
-
-    @Override
-    public void sync() {
-        getFuture(queue(new EmptyTask()));
-    }
-
-    private <T> T getFuture(Future<T> future) {
-        try {
-            return future.get();
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        } catch (ExecutionException e) {
-            throw new RuntimeException(e);
-        } catch (CancellationException e) {
-            // bury the cancel request so that the help methods don't
-            // throw exceptions when the framework is being destroyed
-            return null;
-        }
-    }
-
-    @Override
-    public Status getStatus(Resource resource) {
-        return resourceManager.getStatus(resource);
-    }
-
-    @Override
-    public String getStatusMessage(Resource resource) {
-        return resourceManager.getStatusMessage(resource);
-    }
-
-    @Override
-    public RenderCapabilities getCapabilities() {
-        return renderCaps;
-    }
-
-    @Override
-    public DisplayMode[] getAvailableDisplayModes() {
-        return surfaceFactory.getAvailableDisplayModes();
-    }
-
-    @Override
-    public DisplayMode getDefaultDisplayMode() {
-        return surfaceFactory.getDefaultDisplayMode();
-    }
-
-    @Override
-    public OnscreenSurface getFullscreenSurface() {
-        synchronized (fullscreenLock) {
-            return fullscreenSurface;
-        }
-    }
-
-    /**
-     * @return The ResourceManager that handles the updates and disposals of all known
-     *         resources
-     */
-    public ResourceManager getResourceManager() {
-        return resourceManager;
-    }
-
-    /**
-     * @return The ContextManager that handles threading for the contexts of all created
-     *         surfaces
-     */
-    public ContextManager getContextManager() {
-        return contextManager;
-    }
-
-    /**
-     * @return The LifeCycleManager that controls the Framework's lifecycle
-     *         implementation
-     */
-    public LifeCycleManager getLifeCycleManager() {
-        return lifecycleManager;
-    }
-
-    /**
-     * Remove the given surface from the framework's set of active lists.
-     *
-     * @param surface The surface to remove
-     *
-     * @throws NullPointerException if surface is null
-     */
-    void markSurfaceDestroyed(AbstractSurface surface) {
-        if (surface == null) {
-            throw new NullPointerException("Surface cannot be null");
-        }
-
-        if (surfaces.remove(surface)) {
-            if (surface instanceof TextureSurface) {
-                // Mark all textures as non-disposable
-                TextureSurface ts = (TextureSurface) surface;
-                if (ts.getDepthBuffer() != null) {
-                    resourceManager.setDisposable(ts.getDepthBuffer(), false);
-                }
-                for (int i = 0; i < ts.getNumColorBuffers(); i++) {
-                    resourceManager.setDisposable(ts.getColorBuffer(i), false);
-                }
-            } else if (surface instanceof OnscreenSurface) {
-                if (((OnscreenSurface) surface).getOptions().getFullscreenMode() !=
-                    null) {
-                    synchronized (fullscreenLock) {
-                        // last double check (probably unneeded)
-                        if (fullscreenSurface == surface) {
-                            fullscreenSurface = null;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /*
-     * Internal Callable that runs a single Task with a new
-     * HardwareAccessLayerImpl instance.
-     */
-    private class TaskCallable<T> implements Callable<T> {
-        private final Task<T> task;
-
-        public TaskCallable(Task<T> task) {
-            this.task = task;
-        }
-
-        @Override
-        public T call() throws Exception {
-            return task.run(new HardwareAccessLayerImpl(AbstractFramework.this));
-        }
-    }
-}

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractGlslRenderer.java

 package com.ferox.renderer.impl;
 
 import com.ferox.math.*;
-import com.ferox.renderer.ContextState;
-import com.ferox.renderer.GlslRenderer;
-import com.ferox.renderer.RenderCapabilities;
-import com.ferox.renderer.Renderer;
+import com.ferox.renderer.*;
+import com.ferox.renderer.geom.VertexBufferObject;
 import com.ferox.renderer.impl.drivers.GlslShaderHandle;
 import com.ferox.renderer.impl.drivers.GlslShaderHandle.Attribute;
-import com.ferox.renderer.impl.drivers.GlslShaderHandle.Uniform;
 import com.ferox.renderer.impl.drivers.TextureHandle;
 import com.ferox.renderer.impl.drivers.VertexBufferObjectHandle;
-import com.ferox.resource.*;
+import com.ferox.renderer.texture.Texture.Target;
+import com.ferox.renderer.texture.TextureFormat;
 import com.ferox.resource.GlslShader.AttributeType;
-import com.ferox.resource.GlslUniform.UniformType;
-import com.ferox.resource.Texture.Target;
+import com.ferox.resource.Uniform.UniformType;
 
 import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
     }
 
     protected class UniformBinding {
-        public final Uniform uniform;
+        public final GlslShaderHandle.Uniform uniform;
 
         public final FloatBuffer floatValues;
         public final IntBuffer intValues;
         public boolean valuesValid;
         public boolean isTextureBinding;
 
-        public UniformBinding(Uniform uniform, UniformBinding old) {
+        public UniformBinding(GlslShaderHandle.Uniform uniform, UniformBinding old) {
             this.uniform = uniform;
 
             floatValues = old.floatValues;
             isTextureBinding = old.isTextureBinding;
         }
 
-        public UniformBinding(Uniform uniform) {
+        public UniformBinding(GlslShaderHandle.Uniform uniform) {
             this.uniform = uniform;
             isTextureBinding = false;
             valuesValid = false;
         super.activate(surface, context, manager);
 
         if (textureBindings == null) {
-            RenderCapabilities caps = surface.getFramework().getCapabilities();
+            Capabilities caps = surface.getFramework().getCapabilities();
             int numTextures = Math.max(caps.getMaxVertexShaderTextures(),
                                        caps.getMaxFragmentShaderTextures());
             textureBindings = new TextureBinding[numTextures];
 
                 // fill in the uniform bindings
                 uniformBindings = new HashMap<String, UniformBinding>();
-                for (Entry<String, Uniform> u : shaderHandle.uniforms.entrySet()) {
+                for (Entry<String, GlslShaderHandle.Uniform> u : shaderHandle.uniforms
+                                                                             .entrySet()) {
                     uniformBindings.put(u.getKey(), new UniformBinding(u.getValue()));
                 }
             } else {
     }
 
     @Override
-    public Map<String, GlslUniform> getUniforms() {
+    public Map<String, Uniform> getUniforms() {
         if (shader == null) {
             return Collections.emptyMap();
         }
 
-        Uniform uniform;
-        Map<String, GlslUniform> uniforms = new HashMap<String, GlslUniform>();
+        GlslShaderHandle.Uniform uniform;
+        Map<String, Uniform> uniforms = new HashMap<String, Uniform>();
         for (Entry<String, UniformBinding> u : uniformBindings.entrySet()) {
             uniform = u.getValue().uniform;
             uniforms.put(uniform.name, uniform.uniform);
      * Set the given uniform's values. The uniform could have any of the FLOAT_ types and
      * could possibly be an array. The buffer will have been rewound already.
      */
-    protected abstract void glUniform(Uniform u, FloatBuffer values, int count);
+    protected abstract void glUniform(GlslShaderHandle.Uniform u, FloatBuffer values,
+                                      int count);
 
     @Override
     public void setUniform(String name, float v1, float v2, float v3) {
             return; // ignore unsupported uniforms
         }
 
-        GlslUniform uniform = u.uniform.uniform;
+        Uniform uniform = u.uniform.uniform;
         int primitiveCount = uniform.getType().getPrimitiveCount();
         if (vals.length % primitiveCount != 0) {
             throw new IllegalArgumentException(
      * Set the given uniform's values. The uniform could have any of the INT_ types, the
      * BOOL type or any of the texture sampler types, and could possibly be an array.
      */
-    protected abstract void glUniform(Uniform u, IntBuffer values, int count);
+    protected abstract void glUniform(GlslShaderHandle.Uniform u, IntBuffer values,
+                                      int count);
 
     @Override
     public void setUniform(String name, int v1, int v2) {
             return; // ignore unsupported uniforms
         }
 
-        GlslUniform uniform = u.uniform.uniform;
+        Uniform uniform = u.uniform.uniform;
         int primitiveCount = uniform.getType().getPrimitiveCount();
         if (vals.length % primitiveCount != 0) {
             throw new IllegalArgumentException(
             return; // ignore unsupported uniforms
         }
 
-        GlslUniform uniform = u.uniform.uniform;
+        Uniform uniform = u.uniform.uniform;
         if (uniform.getLength() != vals.length) {
             throw new IllegalArgumentException("Number of elements ( " + vals.length +
                                                ") does not equal the length of uniform " +

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractOnscreenSurface.java

  */
 public abstract class AbstractOnscreenSurface extends AbstractSurface
         implements OnscreenSurface {
-    public AbstractOnscreenSurface(AbstractFramework framework) {
+    public AbstractOnscreenSurface(FrameworkImpl framework) {
         super(framework);
     }
 }

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractRenderer.java

 import com.ferox.math.Const;
 import com.ferox.math.Vector4;
 import com.ferox.renderer.Renderer;
-import com.ferox.resource.VertexBufferObject;
+import com.ferox.renderer.geom.VertexBufferObject;
 
 /**
  * <p/>

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractSurface.java

 
 /**
  * AbstractSurface is an abstract class implementing Surface. Its primary purpose is to
- * expose additional functionality needed by the components of {@link AbstractFramework}
- * to implement the framework system easily across many adapters for OpenGL.
+ * expose additional functionality needed by the components of {@link FrameworkImpl} to
+ * implement the framework system easily across many adapters for OpenGL.
  *
  * @author Michael Ludwig
  */
 public abstract class AbstractSurface implements Surface {
     private final AtomicBoolean destroyed;
-    private final AbstractFramework framework;
+    private final FrameworkImpl framework;
 
     /**
      * Create a new AbstractSurface that has yet to be destroyed, that is owned by the
      *
      * @throws NullPointerException if framework is null
      */
-    public AbstractSurface(AbstractFramework framework) {
+    public AbstractSurface(FrameworkImpl framework) {
         if (framework == null) {
             throw new NullPointerException("Framework cannot be null");
         }
      *                appropriate target
      */
     public void onSurfaceActivate(OpenGLContext context, int layer) {
-        RenderCapabilities caps = context.getRenderCapabilities();
+        Capabilities caps = context.getRenderCapabilities();
         FixedFunctionRenderer ffp = context.getRendererProvider()
                                            .getFixedFunctionRenderer(caps);
         if (ffp instanceof AbstractRenderer) {
     public void onSurfaceDeactivate(OpenGLContext context) {
         // Reset the renderers so that the next task sees a clean slate
         // and any locked resources get released
-        RenderCapabilities caps = context.getRenderCapabilities();
+        Capabilities caps = context.getRenderCapabilities();
         FixedFunctionRenderer ffp = context.getRendererProvider()
                                            .getFixedFunctionRenderer(caps);
         if (ffp != null) {
                                 }
                             }, true);
         } else {
-            System.out.println("Destroy already completed");
             // If we've already been destroyed, use a completed future so
             // it's seen as completed
-            return new CompletedFuture<Void>(null);
+            return new CompletedFuture<>(null);
         }
     }
 
     }
 
     @Override
-    public AbstractFramework getFramework() {
+    public FrameworkImpl getFramework() {
         return framework;
     }
 }

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/AbstractTextureSurface.java

  */
 package com.ferox.renderer.impl;
 
-import com.ferox.renderer.RenderCapabilities;
+import com.ferox.renderer.Capabilities;
+import com.ferox.renderer.Resource.Status;
 import com.ferox.renderer.SurfaceCreationException;
 import com.ferox.renderer.TextureSurface;
 import com.ferox.renderer.TextureSurfaceOptions;
+import com.ferox.renderer.texture.Texture;
+import com.ferox.renderer.texture.Texture.Target;
+import com.ferox.renderer.texture.TextureFormat;
 import com.ferox.resource.BufferData.DataType;
 import com.ferox.resource.Mipmap;
-import com.ferox.resource.Resource.Status;
-import com.ferox.resource.Texture;
-import com.ferox.resource.Texture.Target;
-import com.ferox.resource.TextureFormat;
 
 /**
  * AbstractTextureSurface is a mostly complete implementation of TextureSurface that is
     private final Object[] colorLocks;
     private Object depthLock;
 
-    public AbstractTextureSurface(AbstractFramework framework,
+    public AbstractTextureSurface(FrameworkImpl framework,
                                   TextureSurfaceOptions options) {
         super(framework);
         if (options == null) {
             options = new TextureSurfaceOptions();
         }
 
-        RenderCapabilities caps = framework.getCapabilities();
+        Capabilities caps = framework.getCapabilities();
         options = validateFormat(options, caps);
         options = validateDimensions(options, caps);
 
      */
 
     private static TextureSurfaceOptions validateFormat(TextureSurfaceOptions options,
-                                                        RenderCapabilities caps) {
+                                                        Capabilities caps) {
         int numBuffers = Math
                 .min(caps.getMaxColorBuffers(), options.getNumColorBuffers());
 
     }
 
     private static TextureSurfaceOptions validateDimensions(TextureSurfaceOptions options,
-                                                            RenderCapabilities caps) {
+                                                            Capabilities caps) {
         // set unneeded dimensions to expected values for target
         switch (options.getTarget()) {
         case T_1D:
     }
 
     private static void updateTextures(Texture[] color, Texture depth,
-                                       AbstractFramework framework) {
+                                       FrameworkImpl framework) {
         ContextManager contextManager = framework.getContextManager();
         if (contextManager.isContextThread()) {
             // Don't use the Framework methods since then we'll deadblock

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/BufferUtil.java

  */
 package com.ferox.renderer.impl;
 
-import com.ferox.resource.BufferData;
-import com.ferox.resource.BufferData.DataType;
+
+import com.ferox.renderer.DataType;
 
 import java.nio.*;
 
         case FLOAT:
             return newFloatBuffer(size);
         case BYTE:
+        case NORMALIZED_BYTE:
+        case UNSIGNED_BYTE:
+        case UNSIGNED_NORMALIZED_BYTE:
             return newByteBuffer(size);
         case INT:
+        case NORMALIZED_INT:
+        case UNSIGNED_INT:
+        case UNSIGNED_NORMALIZED_INT:
+        case INT_BIT_FIELD:
             return newIntBuffer(size);
         case SHORT:
+        case NORMALIZED_SHORT:
+        case UNSIGNED_SHORT:
+        case UNSIGNED_NORMALIZED_SHORT:
             return newShortBuffer(size);
         default:
             throw new IllegalArgumentException();
     }
 
     /**
-     * Create a new Buffer that matches the DataType of the provided BufferData. The
-     * created buffer will have a capacity matching the size of the BufferData. If the
-     * BufferData has a non-null array, the buffer will have the array copied into it. The
-     * returned buffer's position will be 0 and its limit will be at its capacity.
+     * Create a new Buffer from the primitive array. The array instance must be a {@code
+     * int[]}, {@code short[]}, {@code byte[]}, or {@code float[]}. The exact
+     * interpretation of the primitives is irrelevant.
      *
-     * @param data The BufferData to clone into an NIO buffer
+     * @param array The primitive to clone into an NIO buffer
      *
      * @return A new direct Buffer
      *
      * @throws NullPointerException if data is null
      */
-    public static Buffer newBuffer(BufferData data) {
-        switch (data.getDataType()) {
-        case FLOAT:
-            float[] fd = data.getArray();
-            return (fd == null ? newFloatBuffer(data.getLength()) : newFloatBuffer(fd));
-        case BYTE:
-            byte[] bd = data.getArray();
-            return (bd == null ? newByteBuffer(data.getLength()) : newByteBuffer(bd));
-        case SHORT:
-            short[] sd = data.getArray();
-            return (sd == null ? newShortBuffer(data.getLength()) : newShortBuffer(sd));
-        case INT:
-            int[] id = data.getArray();
-            return (id == null ? newIntBuffer(data.getLength()) : newIntBuffer(id));
-        default:
-            throw new IllegalArgumentException();
+    public static Buffer newBuffer(Object array) {
+        if (array instanceof float[]) {
+            return newFloatBuffer((float[]) array);
+        } else if (array instanceof int[]) {
+            return newIntBuffer((int[]) array);
+        } else if (array instanceof short[]) {
+            return newShortBuffer((short[]) array);
+        } else if (array instanceof byte[]) {
+            return newByteBuffer((byte[]) array);
+        } else {
+            throw new IllegalArgumentException("Unsupported array type: " + array);
         }
     }
 
     /**
-     * Return the Class of Buffer that will be created by {@link #newBuffer(BufferData)}
-     * and {@link #newBuffer(DataType, int)} based on the given DataType. A DataType of
-     * FLOAT creates FloatBuffers; a DataType of BYTE creates ByteBuffers; a type of INT
-     * creates IntBuffers; and a type of SHORT creates ShortBuffers.
+     * Return the Class of Buffer that will be created by {@link #newBuffer(DataType,
+     * int)} based on the given DataType. A DataType of FLOAT creates FloatBuffers; a
+     * DataType of BYTE creates ByteBuffers; a type of INT creates IntBuffers; and a type
+     * of SHORT creates ShortBuffers.
      *
      * @param type The DataType
      *
         case FLOAT:
             return FloatBuffer.class;
         case BYTE:
+        case NORMALIZED_BYTE:
+        case UNSIGNED_BYTE:
+        case UNSIGNED_NORMALIZED_BYTE:
             return ByteBuffer.class;
         case INT:
+        case NORMALIZED_INT:
+        case UNSIGNED_INT:
+        case UNSIGNED_NORMALIZED_INT:
+        case INT_BIT_FIELD:
             return IntBuffer.class;
         case SHORT:
+        case NORMALIZED_SHORT:
+        case UNSIGNED_SHORT:
+        case UNSIGNED_NORMALIZED_SHORT:
             return ShortBuffer.class;
         }
 

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/ContextManager.java

  * common case where a single surface is rendered into repeatedly.
  * <p/>
  * A newly constructed ContextManager is not ready to use until its {@link
- * #initialize(LifeCycleManager)} is called. The ContextManager is expected to live within
- * the life cycle of its owning Framework (as enforced by the LifeCycleManager).
+ * #initialize(LifeCycleManager, SurfaceFactory)} is called. The ContextManager is
+ * expected to live within the life cycle of its owning Framework (as enforced by the
+ * LifeCycleManager).
  *
  * @author Michael Ludwig
  */
      * LifeCycleManager#start(Runnable)}.
      * <p/>
      * The ContextManager will automatically terminate its threads when it detects that
-     * the LifeCycleManager is being shutdown. All internal threads are managed threads so
-     * the final destruction code passed to {@link LifeCycleManager#destroy(Runnable)}
-     * will not run until the ContextManager stops processing tasks.
+     * the LifeCycleManager is being shutdown. It will continue running tasks until the
+     * manager is fully stopped.
      * <p/>
      * The ContextManager cannot be initialized more than once. It is illegal to use a
      * LifeCycleManager that has a status other than STARTING (i.e. within the scope of
 
         thread = new ContextThread(lifecycle.getManagedThreadGroup(), "gpu-task-thread");
 
-        // Must start a managed thread, but we can't use the convenience method
-        // because the ContextManager uses a special subclass of Thread
-        lifecycle.startManagedThread(thread);
+        // Start the managed thread as a high priority thread so that it can run
+        // while the other threads terminate (and potentially queue tasks)
+        lifecycle.startManagedThread(thread, true); //
 
         // Very first task must be to allocate the shared context
         try {
         try {
             Status status = lifecycleManager.getStatus();
             if (!lifecycleManager.isStopped() ||
-                (acceptOnShutdown && status == Status.STOPPING)) {
+                (acceptOnShutdown && status == Status.STOPPING_LOW_PRIORITY)) {
                 if (isContextThread()) {
                     // don't queue and run the task right away
                     sync.run();
                 } else {
-                    boolean queued = false;
-                    while (!queued) {
-                        queued = thread.tasks.offerLast(sync);
-
+                    // this is written like this to guard against interrupts
+                    boolean queued;
+                    do {
                         try {
-                            if (!queued) {
-                                Thread.sleep(1);
-                            }
+                            queued = thread.tasks
+                                           .offerLast(sync, 5, TimeUnit.MILLISECONDS);
                         } catch (InterruptedException ie) {
+                            queued = false;
                         }
-                    }
+                    } while (!queued);
                 }
             } else {
                 // LifecycleManager is shutting down or already has been, so cancel it
      * <p/>
      * An activated surface that has its own context will continue to have its context
      * current on the thread after the task completes until a new surface is activated
-     * with its own context, or {@link forceRelease(AbstractSurface)} method is called.
+     * with its own context, or {@link #forceRelease(AbstractSurface)} method is called.
      * <p/>
      * Passing in a null Surface will deactivate the currently active surface, and the
      * layer parameter is ignored.
      *
      * @param surface The AbstractSurface to activate
      * @param layer   The layer to activate, will be passed directly to {@link
-     *                AbstractSurface#onSurfaceActivate(int)}
+     *                AbstractSurface#onSurfaceActivate(OpenGLContext, int)}
      *
      * @return The OpenGLContext that is current after this surface has been activated
      *
      * @throws IllegalStateException if {@link #isContextThread()} returns false
      */
+    // FIXME how do we specify the render targets? Is that a later part of the
+    // surface activation specific to the texture surfaces? e.g. it's something
+    // the hardware access layer is concerned with and not the context manager?
+    //
+    // This seems reasonable; we can also move surface activation/deactivation there?
+    // or at least move renderer resetting to the hardware access layer
     public OpenGLContext setActiveSurface(AbstractSurface surface, int layer) {
         // Further validation is handled in the ContextThread after the lock is made
         Thread current = Thread.currentThread();
 
         @Override
         public void run() {
-            // loop until we hit WAITING_ON_CHILDREN, so that we still process
-            // tasks while in the STOPPING stage
-            while (lifecycleManager.getStatus().compareTo(Status.WAITING_ON_CHILDREN) <
+            // loop until we hit STOPPING_HIGH_PRIORITY, so that we still process tasks while in that stage
+            // transition to STOPPED until all children are done
+            while (lifecycleManager.getStatus().compareTo(Status.STOPPING_HIGH_PRIORITY) <
                    0) {
                 // Grab a single task from the queue and run it
                 // Unlocking a surface is handled by pushing a special task

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/DestructibleManager.java

+package com.ferox.renderer.impl;
+
+import com.ferox.renderer.Destructible;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Future;
+
+/**
+ * DestructibleManager controls a thread that monitors registered {@link
+ * Destructible}/{@link ManagedDestructible} pairs of instances. When the Destructible
+ * instance is weak-referenceable the ManagedDestructible is destroyed.  The
+ * ManagedDestructible will be strong-referenced so it will not be garbage collected
+ * before its destroy() method has been invoked.
+ *
+ * @author Michael Ludwig
+ */
+public class DestructibleManager {
+    /**
+     * ManagedDestructible is an interface like {@link Destructible} except that it
+     * doesn't have the requirement that the instance cleans up automatically when it is
+     * garbage collected. A managed destructible is the object that is strong referenced
+     * by the DestructibleManager that is destroyed when an exposed Destructible instance
+     * is GC'ed.
+     */
+    public static interface ManagedDestructible {
+        /**
+         * Destroy the instance, just like {@link com.ferox.renderer.Destructible#destroy()}.
+         *
+         * @return A future linked with the actual destruction task
+         */
+        public Future<Void> destroy();
+
+        /**
+         * @return True if {@link #destroy()} has been called
+         */
+        public boolean isDestroyed();
+    }
+
+    private final ReferenceQueue<Destructible> monitors;
+    private final ConcurrentHashMap<ManagedDestructible, Boolean> managedInstances;
+
+    private LifeCycleManager lifecycle;
+
+    /**
+     * Create a new DestructibleManager.
+     */
+    public DestructibleManager() {
+        monitors = new ReferenceQueue<>();
+        managedInstances = new ConcurrentHashMap<>();
+    }
+
+    /**
+     * <p/>
+     * Complete the initialization of this DestructibleManager and start up an inner
+     * thread that handles processing garbage collected Destructibles. This method ties
+     * the DestructibleManager to the life cycle enforced by the given LifeCycleManager.
+     * It is required that this method is called by the DestructibleManager's owner in the
+     * initialization Runnable passed to {@link LifeCycleManager#start(Runnable)}. The
+     * provided LifeCycleManager should be the same manager that was used to initialize
+     * the rest of the framework.
+     * <p/>
+     * The DestructibleManager will automatically terminate its thread when it detects
+     * that the LifeCycleManager is being shutdown.
+     * <p/>
+     * The ResourceManager cannot be initialized more than once. It is illegal to use a
+     * LifeCycleManager that has a status other than STARTING.
+     *
+     * @param lifecycle The LifeCycleManager that controls when the DestructibleManager
+     *                  ends
+     *
+     * @throws NullPointerException  if lifecycle is null
+     * @throws IllegalStateException if lifecycle doesn't have a status of STARTING, or if
+     *                               the DestructibleManager has already been initialized
+     */
+    public void initialize(LifeCycleManager lifecycle) {
+        if (lifecycle == null) {
+            throw new NullPointerException("LifeCycleManager cannot be null");
+        }
+
+        // We are assuming that we're in the right threading situation, so this is safe.
+        // If this is called outside of the manager's lock then all bets are off, but that's their fault.
+        if (lifecycle.getStatus() !=
+            com.ferox.renderer.impl.LifeCycleManager.Status.STARTING) {
+            throw new IllegalStateException(
+                    "LifeCycleManager must have status STARTING, not: " +
+                    lifecycle.getStatus());
+        }
+
+        // Do a simple exclusive lock to check for double-init attempts. This won't hurt threading
+        // since we should already be in lifecycle's write lock.
+        synchronized (this) {
+            if (this.lifecycle != null) {
+                throw new IllegalStateException(
+                        "DestructibleManager already initialized");
+            }
+            this.lifecycle = lifecycle;
+        }
+
+        // start a low priority managed thread
+        Thread destroyer = new Thread(lifecycle.getManagedThreadGroup(),
+                                      new WeakReferenceMonitor(),
+                                      "destructible-gc-thread");
+        destroyer.setDaemon(true);
+        lifecycle.startManagedThread(destroyer, false);
+    }
+
+    /**
+     * Have this DestructibleManager monitor a weak reference to {@code exposed} and
+     * invoke {@link ManagedDestructible#destroy()} on {@code realInstance} when the
+     * public facing instance has been collected.
+     *
+     * @param exposed      The public-facing or shim instance
+     * @param realInstance The actual data-storing instance that can be cleaned up
+     *
+     * @throws NullPointerException if exposed or realInstance are null
+     */
+    public void manage(Destructible exposed, ManagedDestructible realInstance) {
+        if (exposed == null || realInstance == null) {
+            throw new NullPointerException("Destructible instances cannot be null");
+        }
+
+        lifecycle.getLock().lock();
+        try {
+            if (!lifecycle.isStopped()) {
+                managedInstances.put(realInstance, true);
+                new DestructibleReference(exposed, realInstance, monitors);
+            }
+        } finally {
+            lifecycle.getLock().unlock();
+        }
+    }
+
+    private class WeakReferenceMonitor implements Runnable {
+        @Override
+        public void run() {
+            while (!lifecycle.isStopped()) {
+                try {
+                    // The Destructible associated with this data has been GC'ed
+                    DestructibleReference data = (DestructibleReference) monitors
+                            .remove();
+
+                    // Don't block on this, we just need it to be disposed of in the future
+                    // and don't bother accepting during shutdown since the context
+                    // is about to be destroyed then anyway.
+                    data.destructible.destroy();
+                    managedInstances.remove(data.destructible);
+                } catch (InterruptedException e) {
+                    // Do nothing and keep looping
+                }
+            }
+
+            // we're shutting down, but destroy everything that we have at this point,
+            // but because the lifecycle is stopped we know this collection won't be
+            // changing anymore either
+            Iterator<ManagedDestructible> it = managedInstances.keySet().iterator();
+            while (it.hasNext()) {
+                it.next().destroy();
+                it.remove();
+            }
+        }
+    }
+
+    private class DestructibleReference extends WeakReference<Destructible> {
+        final ManagedDestructible destructible;
+
+        public DestructibleReference(Destructible exposedInstance,
+                                     ManagedDestructible realInstance,
+                                     ReferenceQueue<Destructible> queue) {
+            super(exposedInstance, queue);
+            destructible = realInstance;
+        }
+    }
+}

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/FixedFunctionState.java

 import com.ferox.renderer.FixedFunctionRenderer.CombineSource;
 import com.ferox.renderer.FixedFunctionRenderer.TexCoordSource;
 import com.ferox.renderer.Renderer.Comparison;
-import com.ferox.resource.Texture;
-import com.ferox.resource.VertexBufferObject;
+import com.ferox.renderer.geom.VertexBufferObject;
+import com.ferox.renderer.texture.Texture;
 
 import java.util.Arrays;
 

File ferox-renderer/ferox-renderer-impl/src/main/java/com/ferox/renderer/impl/FrameworkImpl.java

+/*
+ * Ferox, a graphics and game library in Java
+ *
+ * Copyright (c) 2012, Michael Ludwig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *     Redistributions of source code must retain the above copyright notice,
+ *         this list of conditions and the following disclaimer.
+ *     Redistributions in binary form must reproduce the above copyright notice,
+ *         this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.ferox.renderer.impl;
+
+import com.ferox.renderer.*;
+import com.ferox.renderer.builder.*;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * FrameworkImpl is an implementation of Framework that delegates all OpenGL specific
+ * operations to a {@link ResourceManager}, {@link ContextManager} and {@link
+ * SurfaceFactory}. Concrete implementations must provide {@link ResourceDriver
+ * ResourceDrivers} for a ResourceManager and an implementation of SurfaceFactory.
+ *
+ * @author Michael Ludwig
+ */
+public class FrameworkImpl implements Framework {
+    private final ManagedFramework impl;
+    private Capabilities renderCaps; // final after initialize() has been called.
+
+    // fullscreen support
+    private final Object fullscreenLock;
+    private OnscreenSurface fullscreenSurface;
+
+    /**
+     * <p/>
+     * Create a new FrameworkImpl. The parameter, <var>numThreads</var> defines the number
+     * of threads that the framework's ContextManager will use. This constructor will also
+     * create an offscreen context that will later be shared with all created surfaces for
+     * this framework. The given SurfaceFactory is used to create surfaces for the
+     * Framework. The list of drivers are given directly to a {@link ResourceManager}.
+     * <p/>
+     * After constructing an AbstractFramework, {@link #initialize()} must be invoked
+     * before it can be used.
+     *
+     * @param surfaceFactory The SurfaceFactory used to create surfaces
+     * @param drivers        A varargs array of ResourceDrivers that handle the low-level
+     *                       graphics work for resources
+     *
+     * @throws NullPointerException if surfaceFactory or any driver is null
+     */
+    public FrameworkImpl(SurfaceFactory surfaceFactory, ResourceDriver... drivers) {
+        if (surfaceFactory == null) {
+            throw new NullPointerException("SurfaceFactory cannot be null");
+        }
+
+        ContextManager contextManager = new ContextManager();
+        ResourceManager resourceManager = new ResourceManager(contextManager, drivers);
+        impl = new ManagedFramework(surfaceFactory,
+                                    new LifeCycleManager(getClass().getSimpleName()),
+                                    new DestructibleManager(), resourceManager,
+                                    contextManager);
+
+        fullscreenLock = new Object();
+        fullscreenSurface = null;
+    }
+
+    /**
+     * Complete the initialization of the framework so that the public interface defined
+     * in {@link Framework} is usable. It is recommended that concrete implementations of
+     * AbstractFramework define a static method that creates the framework and invokes
+     * this method.
+     */
+    public void initialize() {
+        impl.lifecycleManager.start(new Runnable() {
+            @Override
+            public void run() {
+                // Start up the context manager and resource manager
+                impl.contextManager
+                    .initialize(impl.lifecycleManager, impl.surfaceFactory);
+                impl.resourceManager.initialize(impl.lifecycleManager);
+                impl.destructibleManager.initialize(impl.lifecycleManager);
+
+                // register this framework to be auto-destroyed
+                impl.destructibleManager.manage(FrameworkImpl.this, impl);
+
+                // Fetch the RenderCapabilities now, we do it this way to improve
+                // the Framework creation time instead of forcing OpenGL wrappers to
+                // create and discard a context solely for capabilities detection.
+                Future<Capabilities> caps = impl.contextManager.invokeOnContextThread(
+                        new Callable<Capabilities>() {
+                            @Override
+                            public Capabilities call() throws Exception {
+                                OpenGLContext context = impl.contextManager
+                                                            .ensureContext();
+                                return context.getRenderCapabilities();
+                            }
+                        }, false);
+
+                renderCaps = getFuture(caps);
+            }
+        });
+    }
+
+    @Override
+    public OnscreenSurface createSurface(final OnscreenSurfaceOptions options) {
+        // This task is not accepted during shutdown
+        Future<OnscreenSurface> create = impl.contextManager.invokeOnContextThread(
+                new CreateOnscreenSurface(options), false);
+        return getFuture(create);
+    }
+
+
+    @Override
+    public TextureSurface createSurface(final TextureSurfaceOptions options) {
+        // This task is not accepted during shutdown
+        Future<TextureSurface> create = impl.contextManager.invokeOnContextThread(
+                new CreateTextureSurface(options), false);
+
+        return getFuture(create);
+    }
+
+    @Override
+    public Future<Void> destroy() {
+        return impl.destroy();
+    }
+
+    @Override
+    public boolean isDestroyed() {
+        return impl.isDestroyed();
+    }
+
+    @Override
+    public <T> Future<T> invoke(Task<T> task) {
+        // Specify false so that these tasks are only queued while the state is ACTIVE
+        return impl.contextManager.invokeOnContextThread(new TaskCallable<>(task), false);
+    }
+
+    @Override
+    public Future<Void> flush(final Surface surface) {
+        return invoke(new Task<Void>() {
+            public Void run(HardwareAccessLayer access) {
+                Context context = access.setActiveSurface(surface);
+                if (context != null) {
+                    context.flush();
+                }
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public void sync() {
+        getFuture(invoke(new Task<Void>() {
+            @Override
+            public Void run(HardwareAccessLayer access) {
+                return null;
+            }
+        }));
+    }
+
+    @Override
+    public VertexBufferBuilder newVertexBuffer() {
+        return null;
+    }
+
+    @Override
+    public ElementBufferBuilder newElementBuffer() {
+        return null;
+    }
+
+    @Override
+    public ShaderBuilder newShader() {
+        return null;
+    }
+
+    @Override
+    public Texture1DBuilder newTexture1D() {
+        return null;
+    }
+
+    @Override
+    public Texture2DBuilder newTexture2D() {
+        return null;
+    }
+
+    @Override
+    public TextureCubeMapBuilder newTextureCubeMap() {
+        return null;
+    }
+
+    @Override
+    public Texture3DBuilder newTexture3D() {
+        return null;
+    }
+
+    @Override
+    public Texture1DArrayBuilder newTexture1DArray() {
+        return null;
+    }
+
+    @Override
+    public Texture2DArrayBuilder newTexture2DArray() {
+        return null;
+    }
+
+    @Override
+    public DepthMap2DBuilder newDepthMap2D() {
+        return null;
+    }
+
+    @Override
+    public DepthCubeMapBuilder newDepthCubeMap() {
+        return null;
+    }
+
+    private <T> T getFuture(Future<T> future) {
+        try {
+            return future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            throw new RuntimeException(e);
+        } catch (CancellationException e) {
+            // bury the cancel request so that the help methods don't
+            // throw exceptions when the framework is being destroyed
+            return null;
+        }
+    }
+
+    @Override
+    public Capabilities getCapabilities() {
+        return renderCaps;
+    }
+
+    @Override
+    public DisplayMode getDefaultDisplayMode() {
+        return impl.surfaceFactory.getDefaultDisplayMode();
+    }
+
+    @Override
+    public OnscreenSurface getFullscreenSurface() {
+        synchronized (fullscreenLock) {
+            return fullscreenSurface;
+        }
+    }
+
+    /**
+     * @return The ResourceManager that handles the updates and disposals of all known
+     *         resources
+     */
+    public ResourceManager getResourceManager() {
+        return impl.resourceManager;
+    }
+
+    /**
+     * @return The ContextManager that handles threading for the contexts of all created
+     *         surfaces
+     */
+    public ContextManager getContextManager() {
+        return impl.contextManager;
+    }
+
+    /**
+     * @return The LifeCycleManager that controls the Framework's lifecycle
+     *         implementation
+     */
+    public LifeCycleManager getLifeCycleManager() {
+        return impl.lifecycleManager;
+    }
+
+    public DestructibleManager getDestructibleManager() {
+        return impl.destructibleManager;
+    }
+
+    /**
+     * Remove the given surface from the framework's set of active lists.
+     *
+     * @param surface The surface to remove
+     *
+     * @throws NullPointerException if surface is null
+     */
+    // FIXME do we even still need the fullscreenSurface and lock?
+    void markSurfaceDestroyed(AbstractSurface surface) {
+        if (surface == null) {
+            throw new NullPointerException("Surface cannot be null");
+        }
+
+        if (surface instanceof OnscreenSurface) {
+            synchronized (fullscreenLock) {
+                if (fullscreenSurface == surface) {
+                    fullscreenSurface = null;
+                }
+            }
+        }
+    }
+
+    /*
+     * Internal Callable that runs a single Task with a new
+     * HardwareAccessLayerImpl instance.
+     */
+    private class TaskCallable<T> implements Callable<T> {
+        private final Task<T> task;
+
+        public TaskCallable(Task<T> task) {
+            this.task = task;
+        }
+
+        @Override
+        public T call() throws Exception {
+            return task.run(new HardwareAccessLayerImpl(FrameworkImpl.this));
+        }
+    }
+
+    private class CreateOnscreenSurface implements Callable<OnscreenSurface> {
+        private final OnscreenSurfaceOptions options;
+
+        public CreateOnscreenSurface(OnscreenSurfaceOptions options) {
+            if (options == null) {
+                throw new NullPointerException("Options cannot be null");
+            }
+            this.options = options;
+        }
+
+        @Override
+        public OnscreenSurface call() throws Exception {
+            synchronized (fullscreenLock) {
+                if (options.getFullscreenMode() != null && fullscreenSurface != null) {
+                    throw new SurfaceCreationException(
+                            "Cannot create fullscreen surface when an existing surface is fullscreen");
+                }
+
+                AbstractOnscreenSurface created = impl.surfaceFactory
+                                                      .createOnscreenSurface(
+                                                              FrameworkImpl.this, options,
+                                                              impl.contextManager
+                                                                  .getSharedContext());
+                if (created.isFullscreen()) {
+                    fullscreenSurface = created;
+                }
+
+                impl.contextManager.setActiveSurface(created, 0);
+                return created;
+            }
+        }
+    }
+
+    private class CreateTextureSurface implements Callable<TextureSurface> {
+        private final TextureSurfaceOptions options;
+
+        public CreateTextureSurface(TextureSurfaceOptions options) {
+            if (options == null) {
+                throw new NullPointerException("Options cannot be null");
+            }
+            this.options = options;
+        }
+
+        @Override
+        public TextureSurface call() throws Exception {
+            AbstractTextureSurface created = impl.surfaceFactory
+                                                 .createTextureSurface(FrameworkImpl.this,
+                                                                       options,
+                                                                       impl.contextManager
+                                                                           .getSharedContext());
+
+            impl.contextManager.setActiveSurface(created, 0);
+            return created;
+        }
+    }
+
+    private static class ManagedFramework
+            implements DestructibleManager.ManagedDestructible {
+        private final SurfaceFactory surfaceFactory;
+
+        private final LifeCycleManager lifecycleManager;
+        private final DestructibleManager destructibleManager;
+        private final ResourceManager resourceManager;
+        private final ContextManager contextManager;
+
+        public ManagedFramework(SurfaceFactory surfaceFactory,
+                                LifeCycleManager lifecycleManager,
+                                DestructibleManager destructibleManager,
+                                ResourceManager resourceManager,
+                                ContextManager contextManager) {
+            this.surfaceFactory = surfaceFactory;
+            this.lifecycleManager = lifecycleManager;
+            this.destructibleManager = destructibleManager;
+            this.resourceManager = resourceManager;
+            this.contextManager = contextManager;
+        }
+
+        @Override
+        public Future<Void> destroy() {
+            return lifecycleManager.stop(new Runnable() {
+                @Override
+                public void run() {
+                    // Don't destroy native surface resources until the very end
+                    surfaceFactory.destroy();
+                }
+            });
+        }
+
+        @Override
+        public boolean isDestroyed() {
+            return lifecycleManager.isStopped();
+        }