Skip to content

Commit

Permalink
bindless textures (#7231)
Browse files Browse the repository at this point in the history
* bindless textures

* unified pass UBOs

* remove gl.getActiveUniform in WebGL2
  • Loading branch information
YunHsiao committed Aug 28, 2020
1 parent 0c5c52e commit c451c8a
Show file tree
Hide file tree
Showing 44 changed files with 303 additions and 273 deletions.
2 changes: 1 addition & 1 deletion cocos/core/3d/builtin/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ export default [
"name": "builtin-standard",
"_uuid": "1baf0fc9-befa-459c-8bdd-af1a450a0319",
"techniques": [
{ "name": "opaque", "passes": [{ "program": "builtin-standard|standard-vs:vert|standard-fs:frag", "properties": { "tilingOffset": { "value": [1, 1, 0, 0], "type": 16 }, "mainColor": { "value": [1, 1, 1, 1], "type": 16, "handleInfo": ["albedo", 0, 16] }, "albedoScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["albedoScaleAndCutoff", 0, 15] }, "alphaThreshold": { "value": [0.5], "type": 13, "handleInfo": ["albedoScaleAndCutoff", 3, 13] }, "occlusion": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 0, 13] }, "roughness": { "value": [0.8], "type": 13, "handleInfo": ["pbrParams", 1, 13] }, "metallic": { "value": [0.6], "type": 13, "handleInfo": ["pbrParams", 2, 13] }, "normalStrenth": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 3, 13] }, "emissive": { "value": [0, 0, 0, 1], "type": 16 }, "emissiveScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["emissiveScaleParam", 0, 15] }, "mainTexture": { "value": "grey", "type": 28, "handleInfo": ["albedoMap", 0, 28] }, "normalMap": { "value": "normal", "type": 28 }, "pbrMap": { "value": "grey", "type": 28 }, "metallicRoughnessMap": { "value": "grey", "type": 28 }, "occlusionMap": { "value": "white", "type": 28 }, "emissiveMap": { "value": "grey", "type": 28 }, "albedo": { "type": 16, "value": [1, 1, 1, 1] }, "albedoScaleAndCutoff": { "type": 16, "value": [1, 1, 1, 0.5] }, "pbrParams": { "type": 16, "value": [1, 0.8, 0.6, 1] }, "emissiveScaleParam": { "type": 16, "value": [1, 1, 1, 0] }, "albedoMap": { "type": 28, "value": "grey" } } }, { "phase": "forward-add", "propertyIndex": 0, "embeddedMacros": { "CC_FORWARD_ADD": true }, "blendState": { "targets": [{ "blend": true, "blendSrc": 1, "blendDst": 1, "blendSrcAlpha": 0, "blendDstAlpha": 1 }] }, "program": "builtin-standard|standard-vs:vert|standard-fs:frag", "depthStencilState": { "depthFunc": 2, "depthTest": true, "depthWrite": false }, "properties": { "tilingOffset": { "value": [1, 1, 0, 0], "type": 16 }, "mainColor": { "value": [1, 1, 1, 1], "type": 16, "handleInfo": ["albedo", 0, 16] }, "albedoScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["albedoScaleAndCutoff", 0, 15] }, "alphaThreshold": { "value": [0.5], "type": 13, "handleInfo": ["albedoScaleAndCutoff", 3, 13] }, "occlusion": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 0, 13] }, "roughness": { "value": [0.8], "type": 13, "handleInfo": ["pbrParams", 1, 13] }, "metallic": { "value": [0.6], "type": 13, "handleInfo": ["pbrParams", 2, 13] }, "normalStrenth": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 3, 13] }, "emissive": { "value": [0, 0, 0, 1], "type": 16 }, "emissiveScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["emissiveScaleParam", 0, 15] }, "mainTexture": { "value": "grey", "type": 28, "handleInfo": ["albedoMap", 0, 28] }, "normalMap": { "value": "normal", "type": 28 }, "pbrMap": { "value": "grey", "type": 28 }, "metallicRoughnessMap": { "value": "grey", "type": 28 }, "occlusionMap": { "value": "white", "type": 28 }, "emissiveMap": { "value": "grey", "type": 28 }, "albedo": { "type": 16, "value": [1, 1, 1, 1] }, "albedoScaleAndCutoff": { "type": 16, "value": [1, 1, 1, 0.5] }, "pbrParams": { "type": 16, "value": [1, 0.8, 0.6, 1] }, "emissiveScaleParam": { "type": 16, "value": [1, 1, 1, 0] }, "albedoMap": { "type": 28, "value": "grey" } } }, { "phase": "shadow-add", "rasterizerState": { "cullMode": 1 }, "program": "builtin-standard|shadowMap-vs:vert|shadowMap-fs:frag" }] }
{ "name": "opaque", "passes": [{ "program": "builtin-standard|standard-vs:vert|standard-fs:frag", "properties": { "tilingOffset": { "value": [1, 1, 0, 0], "type": 16 }, "mainColor": { "value": [1, 1, 1, 1], "type": 16, "handleInfo": ["albedo", 0, 16] }, "albedoScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["albedoScaleAndCutoff", 0, 15] }, "alphaThreshold": { "value": [0.5], "type": 13, "handleInfo": ["albedoScaleAndCutoff", 3, 13] }, "occlusion": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 0, 13] }, "roughness": { "value": [0.8], "type": 13, "handleInfo": ["pbrParams", 1, 13] }, "metallic": { "value": [0.6], "type": 13, "handleInfo": ["pbrParams", 2, 13] }, "normalStrenth": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 3, 13] }, "emissive": { "value": [0, 0, 0, 1], "type": 16 }, "emissiveScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["emissiveScaleParam", 0, 15] }, "mainTexture": { "value": "grey", "type": 28, "handleInfo": ["albedoMap", 0, 28] }, "normalMap": { "value": "normal", "type": 28 }, "pbrMap": { "value": "grey", "type": 28 }, "metallicRoughnessMap": { "value": "grey", "type": 28 }, "occlusionMap": { "value": "white", "type": 28 }, "emissiveMap": { "value": "grey", "type": 28 }, "albedo": { "type": 16, "value": [1, 1, 1, 1] }, "albedoScaleAndCutoff": { "type": 16, "value": [1, 1, 1, 0.5] }, "pbrParams": { "type": 16, "value": [1, 0.8, 0.6, 1] }, "emissiveScaleParam": { "type": 16, "value": [1, 1, 1, 0] }, "albedoMap": { "type": 28, "value": "grey" } } }, { "phase": "forward-add", "propertyIndex": 0, "embeddedMacros": { "CC_FORWARD_ADD": true }, "blendState": { "targets": [{ "blend": true, "blendSrc": 1, "blendDst": 1, "blendSrcAlpha": 0, "blendDstAlpha": 1 }] }, "program": "builtin-standard|standard-vs:vert|standard-fs:frag", "depthStencilState": { "depthFunc": 2, "depthTest": true, "depthWrite": false }, "properties": { "tilingOffset": { "value": [1, 1, 0, 0], "type": 16 }, "mainColor": { "value": [1, 1, 1, 1], "type": 16, "handleInfo": ["albedo", 0, 16] }, "albedoScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["albedoScaleAndCutoff", 0, 15] }, "alphaThreshold": { "value": [0.5], "type": 13, "handleInfo": ["albedoScaleAndCutoff", 3, 13] }, "occlusion": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 0, 13] }, "roughness": { "value": [0.8], "type": 13, "handleInfo": ["pbrParams", 1, 13] }, "metallic": { "value": [0.6], "type": 13, "handleInfo": ["pbrParams", 2, 13] }, "normalStrenth": { "value": [1], "type": 13, "handleInfo": ["pbrParams", 3, 13] }, "emissive": { "value": [0, 0, 0, 1], "type": 16 }, "emissiveScale": { "value": [1, 1, 1], "type": 15, "handleInfo": ["emissiveScaleParam", 0, 15] }, "mainTexture": { "value": "grey", "type": 28, "handleInfo": ["albedoMap", 0, 28] }, "normalMap": { "value": "normal", "type": 28 }, "pbrMap": { "value": "grey", "type": 28 }, "metallicRoughnessMap": { "value": "grey", "type": 28 }, "occlusionMap": { "value": "white", "type": 28 }, "emissiveMap": { "value": "grey", "type": 28 }, "albedo": { "type": 16, "value": [1, 1, 1, 1] }, "albedoScaleAndCutoff": { "type": 16, "value": [1, 1, 1, 0.5] }, "pbrParams": { "type": 16, "value": [1, 0.8, 0.6, 1] }, "emissiveScaleParam": { "type": 16, "value": [1, 1, 1, 0] }, "albedoMap": { "type": 28, "value": "grey" } } }, { "phase": "shadow-add", "propertyIndex": 0, "rasterizerState": { "cullMode": 1 }, "program": "builtin-standard|shadowMap-vs:vert|shadowMap-fs:frag" }] }
],
"shaders": [
{
Expand Down
32 changes: 21 additions & 11 deletions cocos/core/assets/material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,23 +422,33 @@ export class Material extends Asset {
}
} else if (propertyType === PropertyType.SAMPLER) {
const binding = Pass.getBindingFromHandle(handle);
if (val instanceof GFXTexture) {
pass.bindTexture(binding, val);
} else if (val instanceof TextureBase || val instanceof SpriteFrame || val instanceof RenderTexture) {
const texture: GFXTexture | null = val.getGFXTexture();
if (!texture || !texture.width || !texture.height) {
// console.warn(`material '${this._uuid}' received incomplete texture asset '${val._uuid}'`);
return false;
if (Array.isArray(val)) {
for (let i = 0; i < val.length; i++) {
this._bindTexture(pass, binding, val[i], i);
}
pass.bindTexture(binding, texture);
pass.bindSampler(binding, val.getGFXSampler());
} else if (!val) {
pass.resetTexture(name);
} else {
this._bindTexture(pass, binding, val);
}
}
return true;
}

protected _bindTexture (pass: Pass, binding: number, val: MaterialPropertyFull, index?: number) {
if (val instanceof GFXTexture) {
pass.bindTexture(binding, val, index);
} else if (val instanceof TextureBase || val instanceof SpriteFrame || val instanceof RenderTexture) {
const texture: GFXTexture | null = val.getGFXTexture();
if (!texture || !texture.width || !texture.height) {
// console.warn(`material '${this._uuid}' received incomplete texture asset '${val._uuid}'`);
return false;
}
pass.bindTexture(binding, texture, index);
pass.bindSampler(binding, val.getGFXSampler(), index);
} else if (!val) {
pass.resetTexture(name, index);
}
}

protected _doDestroy () {
if (this._passes && this._passes.length) {
for (const pass of this._passes) {
Expand Down
6 changes: 6 additions & 0 deletions cocos/core/gfx/descriptor-set-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ export abstract class GFXDescriptorSetLayout extends GFXObject {
return this._bindings;
}

get descriptorIndices () {
return this._descriptorIndices;
}

protected _device: GFXDevice;

protected _bindings: IGFXDescriptorSetLayoutBinding[] = [];

protected _descriptorIndices: number[] = [];

constructor (device: GFXDevice) {
super(GFXObjectType.DESCRIPTOR_SET_LAYOUT);
this._device = device;
Expand Down
48 changes: 27 additions & 21 deletions cocos/core/gfx/descriptor-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ export abstract class GFXDescriptorSet extends GFXObject {
* @param binding The target binding.
* @param buffer The buffer to be bound.
*/
public bindBuffer (binding: number, buffer: GFXBuffer) {
const descriptor = this._layout!.bindings[binding];
if (descriptor && (descriptor.descriptorType & DESCRIPTOR_BUFFER_TYPE)) {
if (this._buffers[binding] !== buffer) {
this._buffers[binding] = buffer;
public bindBuffer (binding: number, buffer: GFXBuffer, index = 0) {
const info = this._layout!.bindings[binding];
const descriptorIndex = this._layout!.descriptorIndices[binding];
if (info && (info.descriptorType & DESCRIPTOR_BUFFER_TYPE)) {
if (this._buffers[descriptorIndex + index] !== buffer) {
this._buffers[descriptorIndex + index] = buffer;
this._isDirty = true;
}
} else {
Expand All @@ -73,11 +74,12 @@ export abstract class GFXDescriptorSet extends GFXObject {
* @param binding The target binding.
* @param sampler The sampler to be bound.
*/
public bindSampler (binding: number, sampler: GFXSampler) {
const descriptor = this._layout!.bindings[binding];
if (descriptor && (descriptor.descriptorType & DESCRIPTOR_SAMPLER_TYPE)) {
if (this._samplers[binding] !== sampler) {
this._samplers[binding] = sampler;
public bindSampler (binding: number, sampler: GFXSampler, index = 0) {
const info = this._layout!.bindings[binding];
const descriptorIndex = this._layout!.descriptorIndices[binding];
if (info && (info.descriptorType & DESCRIPTOR_SAMPLER_TYPE)) {
if (this._samplers[descriptorIndex + index] !== sampler) {
this._samplers[descriptorIndex + index] = sampler;
this._isDirty = true;
}
} else {
Expand All @@ -91,11 +93,12 @@ export abstract class GFXDescriptorSet extends GFXObject {
* @param binding The target binding.
* @param texture The texture to be bound.
*/
public bindTexture (binding: number, texture: GFXTexture) {
const descriptor = this._layout!.bindings[binding];
if (descriptor && (descriptor.descriptorType & DESCRIPTOR_SAMPLER_TYPE)) {
if (this._textures[binding] !== texture) {
this._textures[binding] = texture;
public bindTexture (binding: number, texture: GFXTexture, index = 0) {
const info = this._layout!.bindings[binding];
const descriptorIndex = this._layout!.descriptorIndices[binding];
if (info && (info.descriptorType & DESCRIPTOR_SAMPLER_TYPE)) {
if (this._textures[descriptorIndex + index] !== texture) {
this._textures[descriptorIndex + index] = texture;
this._isDirty = true;
}
} else {
Expand All @@ -108,25 +111,28 @@ export abstract class GFXDescriptorSet extends GFXObject {
* @zh 获取当前指定绑定位置上的缓冲。
* @param binding The target binding.
*/
public getBuffer (binding: number) {
return this._buffers[binding];
public getBuffer (binding: number, index = 0) {
const descriptorIndex = this._layout!.descriptorIndices[binding];
return this._buffers[descriptorIndex + index];
}

/**
* @en Get sampler from the specified binding location.
* @zh 获取当前指定绑定位置上的采样器。
* @param binding The target binding.
*/
public getSampler (binding: number) {
return this._samplers[binding];
public getSampler (binding: number, index = 0) {
const descriptorIndex = this._layout!.descriptorIndices[binding];
return this._samplers[descriptorIndex + index];
}

/**
* @en Get texture from the specified binding location.
* @zh 获取当前指定绑定位置上的贴图。
* @param binding The target binding.
*/
public getTexture (binding: number) {
return this._textures[binding];
public getTexture (binding: number, index = 0) {
const descriptorIndex = this._layout!.descriptorIndices[binding];
return this._textures[descriptorIndex + index];
}
}
38 changes: 23 additions & 15 deletions cocos/core/gfx/webgl/webgl-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1569,12 +1569,14 @@ export function WebGLCmdFuncDestroyInputAssembler (device: WebGLDevice, gpuInput
}

interface IWebGLStateCache {
gpuPipelineState: IWebGLGPUPipelineState | null;
gpuInputAssembler: IWebGLGPUInputAssembler | null;
gpuShader: IWebGLGPUShader | null;
glPrimitive: number;
reverseCW: boolean;
}
const gfxStateCache: IWebGLStateCache = {
gpuPipelineState: null,
gpuInputAssembler: null,
gpuShader: null,
glPrimitive: 0,
Expand Down Expand Up @@ -1771,14 +1773,16 @@ export function WebGLCmdFuncBindStates (

const gl = device.gl;
const cache = device.stateCache;
const gpuShader = gfxStateCache.gpuShader = gpuPipelineState && gpuPipelineState.gpuShader;

let isShaderChanged = false;
let glWrapS: number;
let glWrapT: number;
let glMinFilter: number;
let gpuShader: IWebGLGPUShader | null = null;

if (gpuPipelineState) {
// bind pipeline
if (gpuPipelineState && gfxStateCache.gpuPipelineState !== gpuPipelineState) {
gfxStateCache.gpuPipelineState = gpuPipelineState;
gfxStateCache.glPrimitive = gpuPipelineState.glPrimitive;

if (gpuPipelineState.gpuShader) {
Expand All @@ -1789,8 +1793,6 @@ export function WebGLCmdFuncBindStates (
cache.glProgram = glProgram;
isShaderChanged = true;
}

gfxStateCache.gpuShader = gpuShader = gpuPipelineState.gpuShader;
}

// rasterizer state
Expand Down Expand Up @@ -2019,8 +2021,9 @@ export function WebGLCmdFuncBindStates (
target0Cache.blendColorMask = target0.blendColorMask;
}
} // blend state
} // bind pso
} // bind pipeline

// bind descriptor sets
if (gpuPipelineState && gpuPipelineState.gpuPipelineLayout && gpuShader) {

const blockLen = gpuShader.glBlocks.length;
Expand All @@ -2036,14 +2039,15 @@ export function WebGLCmdFuncBindStates (
const gpuBuffer = gpuDescriptor.gpuBuffer;
const dynamicOffsetIndexSet = dynamicOffsetIndices[glBlock.set];
const dynamicOffsetIndex = dynamicOffsetIndexSet && dynamicOffsetIndexSet[glBlock.binding];
if (dynamicOffsetIndex >= 0) offset = dynamicOffsets[dynamicOffsetIndex];

if ('vf32' in gpuBuffer) {
if (dynamicOffsetIndex >= 0) offset = dynamicOffsets[dynamicOffsetIndex] >> 2;
vf32 = gpuBuffer.vf32;
} else {
if (dynamicOffsetIndex >= 0) offset = (dynamicOffsets[dynamicOffsetIndex] + gpuBuffer.offset) >> 2;
offset += gpuBuffer.offset;
vf32 = gpuBuffer.gpuBuffer.vf32;
}
offset >>= 2;
}

if (!vf32) {
Expand Down Expand Up @@ -2212,17 +2216,18 @@ export function WebGLCmdFuncBindStates (
for (let i = 0; i < samplerLen; i++) {
const glSampler = gpuShader.glSamplers[i];
const gpuDescriptorSet = gpuDescriptorSets[glSampler.set];
const gpuDescriptor = gpuDescriptorSet && gpuDescriptorSet.gpuDescriptors[glSampler.binding];

if (!gpuDescriptor || !gpuDescriptor.gpuSampler) {
error(`Sampler binding '${glSampler.name}' at set ${glSampler.set} binding ${glSampler.binding} is not bounded`);
continue;
}
let descriptorIndex = gpuDescriptorSet && gpuDescriptorSet.descriptorIndices[glSampler.binding] || -1;
let gpuDescriptor = gpuDescriptorSet && gpuDescriptorSet.gpuDescriptors[descriptorIndex];

const texUnitLen = glSampler.units.length;
for (let l = 0; l < texUnitLen; l++) {
const texUnit = glSampler.units[l];

if (!gpuDescriptor || !gpuDescriptor.gpuSampler) {
error(`Sampler binding '${glSampler.name}' at set ${glSampler.set} binding ${glSampler.binding} index ${l} is not bounded`);
continue;
}

if (gpuDescriptor.gpuTexture &&
gpuDescriptor.gpuTexture.size > 0) {

Expand Down Expand Up @@ -2305,10 +2310,13 @@ export function WebGLCmdFuncBindStates (
gpuTexture.glMagFilter = gpuSampler.glMagFilter;
}
}

gpuDescriptor = gpuDescriptorSet.gpuDescriptors[++descriptorIndex];
}
}
} // bind descriptor sets

// bind vertex/index buffer
if (gpuInputAssembler && gpuShader &&
(isShaderChanged || gfxStateCache.gpuInputAssembler !== gpuInputAssembler)) {
gfxStateCache.gpuInputAssembler = gpuInputAssembler;
Expand Down Expand Up @@ -2434,8 +2442,8 @@ export function WebGLCmdFuncBindStates (
cache.glEnabledAttribLocs[a] = false;
}
}
} // if (device.useVAO)
}
}
} // bind vertex/index buffer

if (gpuPipelineState) {
const dsLen = gpuPipelineState.dynamicStates.length;
Expand Down
10 changes: 10 additions & 0 deletions cocos/core/gfx/webgl/webgl-descriptor-set-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export class WebGLDescriptorSetLayout extends GFXDescriptorSetLayout {
public initialize (info: IGFXDescriptorSetLayoutInfo) {
Array.prototype.push.apply(this._bindings, info.bindings);

let descriptorCount = 0;
for (let i = 0; i < this._bindings.length; i++) {
const binding = this._bindings[i];
this._descriptorIndices.push(descriptorCount);
descriptorCount += binding.count;
}
this._descriptorIndices.push(descriptorCount);

const dynamicBindings: number[] = [];
for (let i = 0; i < this._bindings.length; i++) {
const binding = this._bindings[i];
Expand All @@ -23,6 +31,8 @@ export class WebGLDescriptorSetLayout extends GFXDescriptorSetLayout {
this._gpuDescriptorSetLayout = {
bindings: this._bindings,
dynamicBindings,
descriptorIndices: this._descriptorIndices,
descriptorCount,
};

return true;
Expand Down

0 comments on commit c451c8a

Please sign in to comment.