-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added compute pass #2993
Added compute pass #2993
Changes from all commits
a0b0228
cacfbee
7829617
f6a546b
fd12159
9484bc0
ddd259f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/*global define*/ | ||
define([ | ||
'../Core/defaultValue', | ||
'../Core/PrimitiveType', | ||
'../Scene/Pass' | ||
], function( | ||
defaultValue, | ||
PrimitiveType, | ||
Pass) { | ||
"use strict"; | ||
|
||
/** | ||
* Represents a command to the renderer for GPU Compute (using old-school GPGPU). | ||
* | ||
* @private | ||
*/ | ||
var ComputeCommand = function(options) { | ||
options = defaultValue(options, defaultValue.EMPTY_OBJECT); | ||
|
||
/** | ||
* The vertex array. If none is provided, a viewport quad will be used. | ||
* | ||
* @type {VertexArray} | ||
* @default undefined | ||
*/ | ||
this.vertexArray = options.vertexArray; | ||
|
||
/** | ||
* The fragment shader source. The default vertex shader is ViewportQuadVS. | ||
* | ||
* @type {ShaderSource} | ||
* @default undefined | ||
*/ | ||
this.fragmentShaderSource = options.fragmentShaderSource; | ||
|
||
/** | ||
* The shader program to apply. | ||
* | ||
* @type {ShaderProgram} | ||
* @default undefined | ||
*/ | ||
this.shaderProgram = options.shaderProgram; | ||
|
||
/** | ||
* An object with functions whose names match the uniforms in the shader program | ||
* and return values to set those uniforms. | ||
* | ||
* @type {Object} | ||
* @default undefined | ||
*/ | ||
this.uniformMap = options.uniformMap; | ||
|
||
/** | ||
* Texture to use for offscreen rendering. | ||
* | ||
* @type {Texture} | ||
* @default undefined | ||
*/ | ||
this.outputTexture = options.outputTexture; | ||
|
||
/** | ||
* Function that is called immediately before the ComputeCommand is executed. Used to | ||
* update any renderer resources. Takes the ComputeCommand as its single argument. | ||
* | ||
* @type {Function} | ||
* @default undefined | ||
*/ | ||
this.preExecute = options.preExecute; | ||
|
||
/** | ||
* Function that is called after the ComputeCommand is executed. Takes the output | ||
* texture as its single argument. | ||
* | ||
* @type {Function} | ||
* @default undefined | ||
*/ | ||
this.postExecute = options.postExecute; | ||
|
||
/** | ||
* Whether the renderer resources will persist beyond this call. If not, they | ||
* will be destroyed after completion. | ||
* | ||
* @type {Boolean} | ||
* @default false | ||
*/ | ||
this.persists = defaultValue(options.persists, false); | ||
|
||
/** | ||
* The pass when to render. Always compute pass. | ||
* | ||
* @type {Pass} | ||
* @default Pass.COMPUTE; | ||
*/ | ||
this.pass = Pass.COMPUTE; | ||
|
||
/** | ||
* The object who created this command. This is useful for debugging command | ||
* execution; it allows us to see who created a command when we only have a | ||
* reference to the command, and can be used to selectively execute commands | ||
* with {@link Scene#debugCommandFilter}. | ||
* | ||
* @type {Object} | ||
* @default undefined | ||
* | ||
* @see Scene#debugCommandFilter | ||
*/ | ||
this.owner = options.owner; | ||
}; | ||
|
||
/** | ||
* Executes the compute command. | ||
* | ||
* @param {Context} context The context that processes the compute command. | ||
*/ | ||
ComputeCommand.prototype.execute = function(computeEngine) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps remove this, and just have the scene do:
What do you think? We could probably do the same with the other commands, but we need to think through it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about this as well. Either way works for me. One downside is the naming would be inconsistent with the other commands: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't have to be in this PR, but I think we can remove those |
||
computeEngine.execute(this); | ||
}; | ||
|
||
return ComputeCommand; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/*global define*/ | ||
define([ | ||
'../Core/BoundingRectangle', | ||
'../Core/Color', | ||
'../Core/ComponentDatatype', | ||
'../Core/defaultValue', | ||
'../Core/defined', | ||
'../Core/defineProperties', | ||
'../Core/destroyObject', | ||
'../Core/DeveloperError', | ||
'../Core/Geometry', | ||
'../Core/GeometryAttribute', | ||
'../Core/PrimitiveType', | ||
'../Shaders/ViewportQuadVS', | ||
'./BufferUsage', | ||
'./ClearCommand', | ||
'./DrawCommand', | ||
'./Framebuffer', | ||
'./RenderState', | ||
'./ShaderProgram' | ||
], function( | ||
BoundingRectangle, | ||
Color, | ||
ComponentDatatype, | ||
defaultValue, | ||
defined, | ||
defineProperties, | ||
destroyObject, | ||
DeveloperError, | ||
Geometry, | ||
GeometryAttribute, | ||
PrimitiveType, | ||
ViewportQuadVS, | ||
BufferUsage, | ||
ClearCommand, | ||
DrawCommand, | ||
Framebuffer, | ||
RenderState, | ||
ShaderProgram) { | ||
"use strict"; | ||
|
||
/** | ||
* @private | ||
*/ | ||
var ComputeEngine = function(context) { | ||
this._context = context; | ||
}; | ||
|
||
var renderStateScratch; | ||
var drawCommandScratch = new DrawCommand({ | ||
primitiveType : PrimitiveType.TRIANGLES | ||
}); | ||
var clearCommandScratch = new ClearCommand({ | ||
color : new Color(0.0, 0.0, 0.0, 0.0) | ||
}); | ||
|
||
function createFramebuffer(context, outputTexture) { | ||
return new Framebuffer({ | ||
context : context, | ||
colorTextures : [outputTexture], | ||
destroyAttachments : false | ||
}); | ||
} | ||
|
||
function createViewportQuadShader(context, fragmentShaderSource) { | ||
return ShaderProgram.fromCache({ | ||
context : context, | ||
vertexShaderSource : ViewportQuadVS, | ||
fragmentShaderSource : fragmentShaderSource, | ||
attributeLocations : { | ||
position : 0, | ||
textureCoordinates : 1 | ||
} | ||
}); | ||
} | ||
|
||
function createRenderState(width, height) { | ||
if ((!defined(renderStateScratch)) || | ||
(renderStateScratch.viewport.width !== width) || | ||
(renderStateScratch.viewport.height !== height)) { | ||
|
||
renderStateScratch = RenderState.fromCache({ | ||
viewport : new BoundingRectangle(0, 0, width, height) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just use a default render state since the pass state with override The way we have it now, we could end up with a ton of cached render states when the user resizes the canvas. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now PassState is a little inflexible with that. Inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll think of some other way to do this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, right. This is probably fine. Right now we would really just have two render states: one for imagery layers and another for the sun. |
||
}); | ||
} | ||
return renderStateScratch; | ||
} | ||
|
||
ComputeEngine.prototype.execute = function(computeCommand) { | ||
//>>includeStart('debug', pragmas.debug); | ||
if (!defined(computeCommand)) { | ||
throw new DeveloperError('computeCommand is required.'); | ||
} | ||
//>>includeEnd('debug'); | ||
|
||
// This may modify the command's resources, so do error checking afterwards | ||
if (defined(computeCommand.preExecute)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is before the potential |
||
computeCommand.preExecute(computeCommand); | ||
} | ||
|
||
//>>includeStart('debug', pragmas.debug); | ||
if (!defined(computeCommand.fragmentShaderSource) && !defined(computeCommand.shaderProgram)) { | ||
throw new DeveloperError('computeCommand.fragmentShaderSource or computeCommand.shaderProgram is required.'); | ||
} | ||
|
||
if (!defined(computeCommand.outputTexture)) { | ||
throw new DeveloperError('computeCommand.outputTexture is required.'); | ||
} | ||
//>>includeEnd('debug'); | ||
|
||
var outputTexture = computeCommand.outputTexture; | ||
var width = outputTexture.width; | ||
var height = outputTexture.height; | ||
|
||
var context = this._context; | ||
var vertexArray = defined(computeCommand.vertexArray) ? computeCommand.vertexArray : context.getViewportQuadVertexArray(); | ||
var shaderProgram = defined(computeCommand.shaderProgram) ? computeCommand.shaderProgram : createViewportQuadShader(context, computeCommand.fragmentShaderSource); | ||
var framebuffer = createFramebuffer(context, outputTexture); | ||
var renderState = createRenderState(width, height); | ||
var uniformMap = computeCommand.uniformMap; | ||
|
||
var clearCommand = clearCommandScratch; | ||
clearCommand.framebuffer = framebuffer; | ||
clearCommand.renderState = renderState; | ||
clearCommand.execute(context); | ||
|
||
var drawCommand = drawCommandScratch; | ||
drawCommand.vertexArray = vertexArray; | ||
drawCommand.renderState = renderState; | ||
drawCommand.shaderProgram = shaderProgram; | ||
drawCommand.uniformMap = uniformMap; | ||
drawCommand.framebuffer = framebuffer; | ||
drawCommand.execute(context); | ||
|
||
framebuffer.destroy(); | ||
|
||
if (!computeCommand.persists) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this will change with pooling, but we need to think through the semantics of |
||
shaderProgram.destroy(); | ||
if (defined(computeCommand.vertexArray)) { | ||
vertexArray.destroy(); | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove empty whitespace. |
||
if (defined(computeCommand.postExecute)) { | ||
computeCommand.postExecute(outputTexture); | ||
} | ||
}; | ||
|
||
ComputeEngine.prototype.isDestroyed = function() { | ||
return false; | ||
}; | ||
|
||
ComputeEngine.prototype.destroy = function() { | ||
return destroyObject(this); | ||
}; | ||
|
||
return ComputeEngine; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have to do anything now, but if we have separate lists for each pass in a future PR as we discussed, it will most likely mean that we don't need this member any more.