vkCmdBlitImage() support texture arrays as source and destination targets.
This commit is contained in:
parent
595470c747
commit
84ffa1844e
@ -36,12 +36,12 @@ class MVKBuffer;
|
||||
|
||||
/** Describes the Metal texture copying parameters. */
|
||||
typedef struct {
|
||||
NSUInteger srcLevel;
|
||||
NSUInteger srcSlice;
|
||||
uint32_t srcLevel;
|
||||
uint32_t srcSlice;
|
||||
MTLOrigin srcOrigin;
|
||||
MTLSize srcSize;
|
||||
NSUInteger dstLevel;
|
||||
NSUInteger dstSlice;
|
||||
uint32_t dstLevel;
|
||||
uint32_t dstSlice;
|
||||
MTLOrigin dstOrigin;
|
||||
} MVKMetalCopyTextureRegion;
|
||||
|
||||
@ -81,10 +81,10 @@ protected:
|
||||
|
||||
/** Describes Metal texture rendering parameters. */
|
||||
typedef struct {
|
||||
NSUInteger srcLevel;
|
||||
NSUInteger srcSlice;
|
||||
NSUInteger dstLevel;
|
||||
NSUInteger dstSlice;
|
||||
uint32_t srcLevel;
|
||||
uint32_t srcSlice;
|
||||
uint32_t dstLevel;
|
||||
uint32_t dstSlice;
|
||||
MVKVertexPosTex vertices[kMVKBlitVertexCount];
|
||||
} MVKMetalBlitTextureRender;
|
||||
|
||||
@ -117,8 +117,8 @@ protected:
|
||||
MTLRenderPassDescriptor* _mtlRenderPassDescriptor;
|
||||
MTLSamplerMinMagFilter _mtlFilter;
|
||||
MTLPixelFormat _mtlPixFmt;
|
||||
MVKRPSKeyBlitImg _blitKey;
|
||||
std::vector<MVKMetalBlitTextureRender> _mtlTexBlitRenders;
|
||||
bool _isDepthFormat;
|
||||
};
|
||||
|
||||
|
||||
|
@ -125,9 +125,11 @@ void MVKCmdBlitImage::setContent(VkImage srcImage,
|
||||
_dstLayout = dstImageLayout;
|
||||
|
||||
_mtlPixFmt = _dstImage->getMTLPixelFormat();
|
||||
_isDepthFormat = mvkMTLPixelFormatIsDepthFormat(_mtlPixFmt);
|
||||
_mtlFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter);
|
||||
|
||||
_blitKey.mtlPixFmt = (uint32_t)_mtlPixFmt;
|
||||
_blitKey.mtlTexType = (uint32_t)_srcImage->getMTLTextureType();
|
||||
|
||||
_commandUse = commandUse;
|
||||
|
||||
// Determine which regions can be copied and which must be rendered to the destination texture
|
||||
@ -298,8 +300,11 @@ void MVKCmdBlitImage::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
|
||||
if ( !srcMTLTex || !dstMTLTex ) { return; }
|
||||
|
||||
bool isDepthFormat = _blitKey.isDepthFormat();
|
||||
bool isArrayType = _blitKey.isArrayType();
|
||||
|
||||
MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
|
||||
mtlColorAttDesc.texture = _isDepthFormat ? nil : dstMTLTex;
|
||||
mtlColorAttDesc.texture = isDepthFormat ? nil : dstMTLTex;
|
||||
|
||||
uint32_t vtxBuffIdx = getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
|
||||
|
||||
@ -314,12 +319,18 @@ void MVKCmdBlitImage::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
mtlRendEnc.label = mvkMTLRenderCommandEncoderLabel(_commandUse);
|
||||
|
||||
[mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
|
||||
[mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdBlitImageMTLRenderPipelineState(_mtlPixFmt)];
|
||||
[mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdBlitImageMTLRenderPipelineState(_blitKey)];
|
||||
cmdEncoder->setVertexBytes(mtlRendEnc, bltRend.vertices, sizeof(bltRend.vertices), vtxBuffIdx);
|
||||
if (_isDepthFormat) {
|
||||
[mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(_isDepthFormat, false)];
|
||||
if (isArrayType) {
|
||||
cmdEncoder->setFragmentBytes(mtlRendEnc, &bltRend, sizeof(bltRend), 0);
|
||||
}
|
||||
if (isDepthFormat) {
|
||||
[mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(isDepthFormat, false)];
|
||||
[mtlRendEnc setVertexTexture: srcMTLTex atIndex: 0];
|
||||
[mtlRendEnc setVertexSamplerState: cmdEncPool->getCmdBlitImageMTLSamplerState(_mtlFilter) atIndex: 0];
|
||||
if (isArrayType) {
|
||||
cmdEncoder->setVertexBytes(mtlRendEnc, &bltRend, sizeof(bltRend), 0);
|
||||
}
|
||||
} else {
|
||||
[mtlRendEnc setFragmentTexture: srcMTLTex atIndex: 0];
|
||||
[mtlRendEnc setFragmentSamplerState: cmdEncPool->getCmdBlitImageMTLSamplerState(_mtlFilter) atIndex: 0];
|
||||
|
@ -43,11 +43,8 @@ public:
|
||||
|
||||
#pragma mark Command resources
|
||||
|
||||
/**
|
||||
* Returns a MTLRenderPipelineState dedicated to rendering to a texture
|
||||
* in the specified pixel format to support certain Vulkan BLIT commands.
|
||||
*/
|
||||
id<MTLRenderPipelineState> getCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt);
|
||||
/** Returns a MTLRenderPipelineState to support certain Vulkan BLIT commands. */
|
||||
id<MTLRenderPipelineState> getCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey);
|
||||
|
||||
/**
|
||||
* Returns a MTLSamplerState dedicated to rendering to a texture using the
|
||||
@ -110,7 +107,7 @@ private:
|
||||
void initTextureDeviceMemory();
|
||||
void destroyMetalResources();
|
||||
|
||||
std::unordered_map<uint32_t, id<MTLRenderPipelineState>> _cmdBlitImageMTLRenderPipelineStates;
|
||||
std::unordered_map<MVKRPSKeyBlitImg, id<MTLRenderPipelineState>> _cmdBlitImageMTLRenderPipelineStates;
|
||||
std::unordered_map<MVKRPSKeyClearAtt, id<MTLRenderPipelineState>> _cmdClearMTLRenderPipelineStates;
|
||||
std::unordered_map<MVKMTLDepthStencilDescriptorData, id<MTLDepthStencilState>> _mtlDepthStencilStates;
|
||||
std::unordered_map<MVKImageDescriptorData, MVKImage*> _transferImages;
|
||||
|
@ -33,11 +33,11 @@ id<MTLRenderPipelineState> MVKCommandEncodingPool::getCmdClearMTLRenderPipelineS
|
||||
return rps;
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> MVKCommandEncodingPool::getCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt) {
|
||||
id<MTLRenderPipelineState> rps = _cmdBlitImageMTLRenderPipelineStates[mtlPixFmt];
|
||||
id<MTLRenderPipelineState> MVKCommandEncodingPool::getCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey) {
|
||||
id<MTLRenderPipelineState> rps = _cmdBlitImageMTLRenderPipelineStates[blitKey];
|
||||
if ( !rps ) {
|
||||
rps = _device->getCommandResourceFactory()->newCmdBlitImageMTLRenderPipelineState(mtlPixFmt); // retained
|
||||
_cmdBlitImageMTLRenderPipelineStates[mtlPixFmt] = rps;
|
||||
rps = _device->getCommandResourceFactory()->newCmdBlitImageMTLRenderPipelineState(blitKey); // retained
|
||||
_cmdBlitImageMTLRenderPipelineStates[blitKey] = rps;
|
||||
}
|
||||
return rps;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ typedef struct {
|
||||
} AttributesPos; \n\
|
||||
\n\
|
||||
typedef struct { \n\
|
||||
float4 gl_Position [[position]]; \n\
|
||||
float4 v_position [[position]]; \n\
|
||||
} VaryingsPos; \n\
|
||||
\n\
|
||||
typedef struct { \n\
|
||||
@ -37,13 +37,20 @@ typedef struct {
|
||||
} AttributesPosTex; \n\
|
||||
\n\
|
||||
typedef struct { \n\
|
||||
float4 gl_Position [[position]]; \n\
|
||||
float4 v_position [[position]]; \n\
|
||||
float2 v_texCoord; \n\
|
||||
} VaryingsPosTex; \n\
|
||||
\n\
|
||||
typedef struct { \n\
|
||||
uint srcLevel; \n\
|
||||
uint srcSlice; \n\
|
||||
uint dstLevel; \n\
|
||||
uint dstSlice; \n\
|
||||
} BlitInfo; \n\
|
||||
\n\
|
||||
vertex VaryingsPosTex vtxCmdBlitImage(AttributesPosTex attributes [[stage_in]]) { \n\
|
||||
VaryingsPosTex varyings; \n\
|
||||
varyings.gl_Position = float4(attributes.a_position, 0.0, 1.0); \n\
|
||||
varyings.v_position = float4(attributes.a_position, 0.0, 1.0); \n\
|
||||
varyings.v_texCoord = attributes.a_texCoord; \n\
|
||||
return varyings; \n\
|
||||
} \n\
|
||||
@ -53,7 +60,17 @@ vertex VaryingsPos vtxCmdBlitImageD(AttributesPosTex attributes [[stage_in]],
|
||||
sampler sampler [[sampler(0)]]) { \n\
|
||||
float depth = texture.sample(sampler, attributes.a_texCoord); \n\
|
||||
VaryingsPos varyings; \n\
|
||||
varyings.gl_Position = float4(attributes.a_position, depth, 1.0); \n\
|
||||
varyings.v_position = float4(attributes.a_position, depth, 1.0); \n\
|
||||
return varyings; \n\
|
||||
} \n\
|
||||
\n\
|
||||
vertex VaryingsPos vtxCmdBlitImageDA(AttributesPosTex attributes [[stage_in]], \n\
|
||||
depth2d_array<float> texture [[texture(0)]], \n\
|
||||
sampler sampler [[sampler(0)]], \n\
|
||||
constant BlitInfo& blitInfo [[buffer(0)]]) { \n\
|
||||
float depth = texture.sample(sampler, attributes.a_texCoord, blitInfo.srcSlice); \n\
|
||||
VaryingsPos varyings; \n\
|
||||
varyings.v_position = float4(attributes.a_position, depth, 1.0); \n\
|
||||
return varyings; \n\
|
||||
} \n\
|
||||
\n\
|
||||
@ -64,7 +81,7 @@ typedef struct {
|
||||
vertex VaryingsPos vtxCmdClearAttachments(AttributesPos attributes [[stage_in]], \n\
|
||||
constant ClearColorsIn& ccIn [[buffer(0)]]) { \n\
|
||||
VaryingsPos varyings; \n\
|
||||
varyings.gl_Position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0); \n\
|
||||
varyings.v_position = float4(attributes.a_position.x, -attributes.a_position.y, ccIn.colors[8].r, 1.0); \n\
|
||||
return varyings; \n\
|
||||
} \n\
|
||||
\n\
|
||||
|
@ -26,6 +26,51 @@
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MVKRPSKeyBlitImg
|
||||
|
||||
/**
|
||||
* Key to use for looking up cached MTLRenderPipelineState instances based on MTLPixelFormat and MTLTextureType.
|
||||
*
|
||||
* This structure can be used as a key in a std::map and std::unordered_map.
|
||||
*/
|
||||
typedef struct MVKRPSKeyBlitImg_t {
|
||||
uint16_t mtlPixFmt = 0; /**< MTLPixelFormat */
|
||||
uint16_t mtlTexType = 0; /**< MTLTextureType */
|
||||
|
||||
bool operator==(const MVKRPSKeyBlitImg_t& rhs) const {
|
||||
return ((mtlPixFmt == rhs.mtlPixFmt) && (mtlTexType == rhs.mtlTexType));
|
||||
}
|
||||
|
||||
inline MTLPixelFormat getMTLPixelFormat() { return (MTLPixelFormat)mtlPixFmt; }
|
||||
|
||||
inline bool isDepthFormat() { return mvkMTLPixelFormatIsDepthFormat(getMTLPixelFormat()); }
|
||||
|
||||
inline MTLTextureType getMTLTextureType() { return (MTLTextureType)mtlTexType; }
|
||||
|
||||
inline bool isArrayType() { return (mtlTexType == MTLTextureType2DArray) || (mtlTexType == MTLTextureType1DArray); }
|
||||
|
||||
std::size_t hash() const {
|
||||
std::size_t hash = mtlTexType;
|
||||
hash <<= 16;
|
||||
hash |= mtlPixFmt;
|
||||
return hash;
|
||||
}
|
||||
|
||||
} MVKRPSKeyBlitImg;
|
||||
|
||||
/**
|
||||
* Hash structure implementation for MVKRPSKeyBlitImg in std namespace,
|
||||
* so MVKRPSKeyBlitImg can be used as a key in a std::map and std::unordered_map.
|
||||
*/
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<MVKRPSKeyBlitImg> {
|
||||
std::size_t operator()(const MVKRPSKeyBlitImg& k) const { return k.hash(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MVKRPSKeyClearAtt
|
||||
|
||||
@ -226,11 +271,8 @@ public:
|
||||
|
||||
#pragma mark Command resources
|
||||
|
||||
/**
|
||||
* Returns a new MTLRenderPipelineState dedicated to rendering to a texture
|
||||
* in the specified pixel format to support certain Vulkan BLIT commands.
|
||||
*/
|
||||
id<MTLRenderPipelineState> newCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt);
|
||||
/** Returns a new MTLRenderPipelineState to support certain Vulkan BLIT commands. */
|
||||
id<MTLRenderPipelineState> newCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey);
|
||||
|
||||
/**
|
||||
* Returns a new MTLSamplerState dedicated to rendering to a texture using the
|
||||
@ -281,7 +323,7 @@ public:
|
||||
|
||||
protected:
|
||||
void initMTLLibrary();
|
||||
id<MTLFunction> getBlitFragFunction(MTLPixelFormat mtlPixFmt);
|
||||
id<MTLFunction> getBlitFragFunction(MVKRPSKeyBlitImg& blitKey);
|
||||
id<MTLFunction> getClearFragFunction(MVKRPSKeyClearAtt& attKey);
|
||||
NSString* getMTLFormatTypeString(MTLPixelFormat mtlPixFmt);
|
||||
id<MTLFunction> getFunctionNamed(const char* funcName);
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "MVKCommandPipelineStateFactoryShaderSource.h"
|
||||
#include "MVKPipeline.h"
|
||||
#include "MVKFoundation.h"
|
||||
#include "mvk_datatypes.h"
|
||||
#include "NSString+MoltenVK.h"
|
||||
#include "MVKLogging.h"
|
||||
|
||||
@ -30,19 +29,20 @@ using namespace std;
|
||||
#pragma mark -
|
||||
#pragma mark MVKCommandResourceFactory
|
||||
|
||||
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdBlitImageMTLRenderPipelineState(MTLPixelFormat mtlPixFmt) {
|
||||
bool isDepthFormat = mvkMTLPixelFormatIsDepthFormat(mtlPixFmt);
|
||||
id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey) {
|
||||
bool isDepthFormat = blitKey.isDepthFormat();
|
||||
bool isArrayType = blitKey.isArrayType();
|
||||
|
||||
MTLRenderPipelineDescriptor* plDesc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
|
||||
plDesc.label = [NSString stringWithFormat: @"CmdBlitImage"];
|
||||
|
||||
plDesc.vertexFunction = getFunctionNamed(isDepthFormat ? "vtxCmdBlitImageD" : "vtxCmdBlitImage");
|
||||
plDesc.fragmentFunction = getBlitFragFunction(mtlPixFmt);
|
||||
plDesc.vertexFunction = getFunctionNamed(isDepthFormat ? (isArrayType ? "vtxCmdBlitImageDA" : "vtxCmdBlitImageD") : "vtxCmdBlitImage");
|
||||
plDesc.fragmentFunction = getBlitFragFunction(blitKey);
|
||||
|
||||
if (isDepthFormat) {
|
||||
plDesc.depthAttachmentPixelFormat = mtlPixFmt;
|
||||
plDesc.depthAttachmentPixelFormat = blitKey.getMTLPixelFormat();
|
||||
} else {
|
||||
plDesc.colorAttachments[0].pixelFormat = mtlPixFmt;
|
||||
plDesc.colorAttachments[0].pixelFormat = blitKey.getMTLPixelFormat();
|
||||
}
|
||||
|
||||
MTLVertexDescriptor* vtxDesc = plDesc.vertexDescriptor;
|
||||
@ -131,10 +131,15 @@ id<MTLRenderPipelineState> MVKCommandResourceFactory::newCmdClearMTLRenderPipeli
|
||||
return newMTLRenderPipelineState(plDesc);
|
||||
}
|
||||
|
||||
id<MTLFunction> MVKCommandResourceFactory::getBlitFragFunction(MTLPixelFormat mtlPixFmt) {
|
||||
id<MTLFunction> MVKCommandResourceFactory::getBlitFragFunction(MVKRPSKeyBlitImg& blitKey) {
|
||||
id<MTLFunction> mtlFunc = nil;
|
||||
bool isDepthFormat = mvkMTLPixelFormatIsDepthFormat(mtlPixFmt);
|
||||
NSString* typeStr = getMTLFormatTypeString(mtlPixFmt);
|
||||
|
||||
bool isDepthFormat = blitKey.isDepthFormat();
|
||||
NSString* typeStr = getMTLFormatTypeString(blitKey.getMTLPixelFormat());
|
||||
|
||||
bool isArrayType = blitKey.isArrayType();
|
||||
NSString* arraySuffix = isArrayType ? @"_array" : @"";
|
||||
NSString* sliceArg = isArrayType ? @", blitInfo.srcSlice" : @"";
|
||||
|
||||
@autoreleasepool {
|
||||
NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ];
|
||||
@ -142,27 +147,41 @@ id<MTLFunction> MVKCommandResourceFactory::getBlitFragFunction(MTLPixelFormat mt
|
||||
[msl appendLineMVK: @"using namespace metal;"];
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"typedef struct {"];
|
||||
[msl appendLineMVK: @" float4 gl_Position [[position]];"];
|
||||
[msl appendLineMVK: @" float4 v_position [[position]];"];
|
||||
[msl appendLineMVK: @" float2 v_texCoord;"];
|
||||
[msl appendLineMVK: @"} VaryingsPosTex;"];
|
||||
[msl appendLineMVK];
|
||||
if (isArrayType) {
|
||||
[msl appendLineMVK: @"typedef struct {"];
|
||||
[msl appendLineMVK: @" uint srcLevel;"];
|
||||
[msl appendLineMVK: @" uint srcSlice;"];
|
||||
[msl appendLineMVK: @" uint dstLevel;"];
|
||||
[msl appendLineMVK: @" uint dstSlice;"];
|
||||
[msl appendLineMVK: @"} BlitInfo;"];
|
||||
[msl appendLineMVK];
|
||||
}
|
||||
|
||||
NSString* funcName = @"fragBlit";
|
||||
[msl appendFormat: @"fragment %@4 %@(VaryingsPosTex varyings [[stage_in]],", typeStr, funcName];
|
||||
[msl appendLineMVK];
|
||||
if (isDepthFormat) {
|
||||
[msl appendLineMVK: @" depth2d<float> texture [[texture(0)]],"];
|
||||
[msl appendFormat: @" depth2d%@<float> texture [[texture(0)]],", arraySuffix];
|
||||
} else {
|
||||
[msl appendFormat: @" texture2d<%@> texture [[texture(0)]],", typeStr];
|
||||
[msl appendLineMVK];
|
||||
[msl appendFormat: @" texture2d%@<%@> texture [[texture(0)]],", arraySuffix, typeStr];
|
||||
}
|
||||
[msl appendLineMVK];
|
||||
if (isArrayType) {
|
||||
[msl appendLineMVK: @" sampler sampler [[sampler(0)]],"];
|
||||
[msl appendLineMVK: @" constant BlitInfo& blitInfo [[buffer(0)]]) {"];
|
||||
} else {
|
||||
[msl appendLineMVK: @" sampler sampler [[sampler(0)]]) {"];
|
||||
if (isDepthFormat) {
|
||||
[msl appendFormat: @" return %@4(texture.sample(sampler, varyings.v_texCoord));", typeStr];
|
||||
[msl appendLineMVK];
|
||||
} else {
|
||||
[msl appendLineMVK: @" return texture.sample(sampler, varyings.v_texCoord);"];
|
||||
}
|
||||
if (isDepthFormat) {
|
||||
[msl appendFormat: @" return %@4(texture.sample(sampler, varyings.v_texCoord)%@);", typeStr, sliceArg];
|
||||
} else {
|
||||
[msl appendFormat: @" return texture.sample(sampler, varyings.v_texCoord%@);", sliceArg];
|
||||
}
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"}"];
|
||||
|
||||
mtlFunc = newMTLFunction(msl, funcName);
|
||||
@ -179,7 +198,7 @@ id<MTLFunction> MVKCommandResourceFactory::getClearFragFunction(MVKRPSKeyClearAt
|
||||
[msl appendLineMVK: @"using namespace metal;"];
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"typedef struct {"];
|
||||
[msl appendLineMVK: @" float4 gl_Position [[position]];"];
|
||||
[msl appendLineMVK: @" float4 v_position [[position]];"];
|
||||
[msl appendLineMVK: @"} VaryingsPos;"];
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"typedef struct {"];
|
||||
|
@ -36,7 +36,7 @@ typedef struct { \n\
|
||||
} Attributes; \n\
|
||||
\n\
|
||||
typedef struct { \n\
|
||||
float4 gl_Position [[position]]; \n\
|
||||
float4 v_position [[position]]; \n\
|
||||
float2 v_texCoord; \n\
|
||||
float4 v_fragColor; \n\
|
||||
} Varyings; \n\
|
||||
@ -44,7 +44,7 @@ typedef struct { \n\
|
||||
vertex Varyings watermarkVertex(Attributes attributes [[stage_in]], \n\
|
||||
constant Uniforms& uniforms [[ buffer(0) ]]) { \n\
|
||||
Varyings varyings; \n\
|
||||
varyings.gl_Position = uniforms.mvpMtx * float4(attributes.a_position, 0.0, 1.0); \n\
|
||||
varyings.v_position = uniforms.mvpMtx * float4(attributes.a_position, 0.0, 1.0); \n\
|
||||
varyings.v_fragColor = uniforms.color; \n\
|
||||
varyings.v_texCoord = attributes.a_texCoord; \n\
|
||||
return varyings; \n\
|
||||
|
Loading…
x
Reference in New Issue
Block a user