Updated mtlPtexViewer to match mtlViewer

These changes update the mtlPtexViewer implementation
to match recent changes to the mtlViewer including:
- improved shader organization
- correct screenspace tessellation
- support for common command line arguments and fit to frame
This commit is contained in:
David G Yu 2019-06-18 15:32:07 -07:00
parent b4ace6791b
commit 78113981e6
4 changed files with 797 additions and 609 deletions

View File

@ -90,12 +90,17 @@ enum {
-(void)keyDown:(NSEvent *)event {
const auto key = [event.charactersIgnoringModifiers characterAtIndex:0];
if(key == '=') {
_controller.osdRenderer.tessellationLevel = std::min(_controller.osdRenderer.tessellationLevel + 1, 16.0f);
if (hud.KeyDown(key)) {
return;
} else if(key == '=') {
_controller.osdRenderer.tessellationLevel = std::min(_controller.osdRenderer.tessellationLevel + 1, 16);
} else if (key == '-') {
_controller.osdRenderer.tessellationLevel = std::max(_controller.osdRenderer.tessellationLevel - 1, 0.0f);
} else if(!hud.KeyDown(key))
_controller.osdRenderer.tessellationLevel = std::max(_controller.osdRenderer.tessellationLevel - 1, 0);
} else if (key == 'f') {
[_controller.osdRenderer fitFrame];
} else {
[super keyDown:event];
}
}
-(void)scrollWheel:(NSEvent *)event {
@ -184,6 +189,9 @@ enum {
case kHUD_CB_FRACTIONAL_SPACING:
self.osdRenderer.useFractionalTessellation = checked;
break;
case kHUD_CB_SEAMLESS_MIPMAP:
self.osdRenderer.useSeamlessMipmap = checked;
break;
default:
assert("Unknown checkbox ID" && 0);
}
@ -397,8 +405,6 @@ enum {
auto commandBuffer = [_commandQueue commandBuffer];
_osdRenderer.displacementScale = 3;
double avg = 0;
for(int i = 0; i < FRAME_HISTORY; i++)
avg += _frameBeginTimestamp[i];
@ -408,7 +414,7 @@ enum {
auto& hud = self.view->hud;
if(hud.IsVisible()) {
hud.DrawString(10, -120, "Tess level : %f", _osdRenderer.tessellationLevel);
hud.DrawString(10, -120, "Tess level : %d", _osdRenderer.tessellationLevel);
hud.DrawString(10, -20, "FPS = %3.1f", 1.0 / avg);
//Disable Culling & Force Fill mode when drawing the UI

View File

@ -63,10 +63,12 @@ typedef struct {
-(id<MTLRenderCommandEncoder>)drawFrame:(id<MTLCommandBuffer>)commandBuffer;
-(void)fitFrame;
@property (readonly, nonatomic) id<OSDRendererDelegate> delegate;
@property (nonatomic) unsigned refinementLevel;
@property (nonatomic) float tessellationLevel;
@property (nonatomic) int tessellationLevel;
@property (readonly, nonatomic) Camera* camera;
@ -77,7 +79,8 @@ typedef struct {
@property (nonatomic) bool usePatchIndexBuffer;
@property (nonatomic) bool usePatchBackfaceCulling;
@property (nonatomic) bool usePatchClipCulling;
@property (nonatomic) bool useSingleCrease;
@property (nonatomic) bool useSmoothCornerPatch;
@property (nonatomic) bool useSingleCreasePatch;
@property (nonatomic) bool useInfinitelySharpPatch;
@property (nonatomic) bool useStageIn;
@property (nonatomic) bool usePrimitiveBackfaceCulling;
@ -88,6 +91,7 @@ typedef struct {
@property (nonatomic) bool displayControlMeshVertices;
@property (nonatomic) bool displaySpecular;
@property (nonatomic) bool displayOcclusion;
@property (nonatomic) bool yup;
@property (nonatomic) float mipmapBias;
@property (nonatomic) float displacementScale;

View File

@ -1,6 +1,6 @@
#line 0 "examples/mtlPtexViewer/mtlPtexViewer.metal"
//
// Copyright 2013 Pixar
// Copyright 2013-2019 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
@ -26,6 +26,10 @@
#include <metal_stdlib>
using namespace metal;
#if OSD_IS_ADAPTIVE
static_assert(!OSD_ENABLE_SCREENSPACE_TESSELLATION || !USE_PTVS_FACTORS, "USE_PTVS_FACTORS cannot be enabled if OSD_ENABLE_SCREENSPACE_TESSELLATION is enabled");
#endif
struct Config {
float displacementScale;
float mipmapBias;
@ -64,11 +68,11 @@ const constant float4 patchColors[] = {
float4(0.0f, 0.8f, 0.75f, 1.0f), // boundary pattern 4
float4(0.0f, 1.0f, 0.0f, 1.0f), // corner
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 0
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 1
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 2
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 3
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 4
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 0
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 1
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 2
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 3
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 4
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
@ -95,33 +99,32 @@ const constant float4 patchColors[] = {
float4
getAdaptivePatchColor(int3 patchParam, float sharpness)
{
int pattern = popcount(OsdGetPatchTransitionMask(patchParam));
int edgeCount = popcount(OsdGetPatchBoundaryMask(patchParam));
int patchType = 0;
#if OSD_PATCH_ENABLE_SINGLE_CREASE
if (sharpness > 0) {
pattern = 1;
}
#endif
int edgeCount = popcount(OsdGetPatchBoundaryMask(patchParam));
if (edgeCount == 1) {
patchType = 2; // BOUNDARY
}
if (edgeCount == 2) {
if (edgeCount > 1) {
patchType = 3; // CORNER
}
// XXX: it looks like edgeCount != 0 for some gregory boundary patches.
// there might be a bug somewhere...
#if OSD_PATCH_GREGORY
#if OSD_PATCH_ENABLE_SINGLE_CREASE
if (sharpness > 0) {
patchType = 1;
}
#elif OSD_PATCH_GREGORY
patchType = 4;
#elif OSD_PATCH_GREGORY_BOUNDARY
patchType = 5;
#elif OSD_PATCH_GREGORY_BASIS
patchType = 6;
#elif OSD_PATCH_GREGORY_TRIANGLE
patchType = 6;
#endif
int pattern = popcount(OsdGetPatchTransitionMask(patchParam));
return patchColors[6*patchType + pattern];
}
@ -248,10 +251,9 @@ struct FragmentInput
#if OSD_IS_ADAPTIVE
#if USE_STAGE_IN
#if OSD_PATCH_REGULAR
#if OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE
struct ControlPoint
{
float3 P [[attribute(0)]];
#if OSD_PATCH_ENABLE_SINGLE_CREASE
float3 P1 [[attribute(1)]];
@ -261,6 +263,21 @@ struct ControlPoint
#endif
#endif
};
#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
struct ControlPoint
{
float3 P [[attribute(0)]];
float3 Ep [[attribute(1)]];
float3 Em [[attribute(2)]];
float3 Fp [[attribute(3)]];
float3 Fm [[attribute(4)]];
};
#elif OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE
struct ControlPoint
{
float3 position [[attribute(0)]];
};
#endif
struct PatchInput
{
@ -271,77 +288,67 @@ struct PatchInput
#endif
int3 patchParam [[attribute(10)]];
};
#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
struct ControlPoint
{
float3 P [[attribute(0)]];
float3 Ep [[attribute(1)]];
float3 Em [[attribute(2)]];
float3 Fp [[attribute(3)]];
float3 Fm [[attribute(4)]];
};
struct PatchInput
{
patch_control_point<ControlPoint> cv;
int3 patchParam [[attribute(10)]];
};
#elif OSD_PATCH_GREGORY_BASIS
struct ControlPoint
{
float3 position [[attribute(0)]];
};
struct PatchInput
{
patch_control_point<ControlPoint> cv;
int3 patchParam [[attribute(10)]];
};
#endif
#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
typedef MTLQuadTessellationFactorsHalf PatchTessFactors;
#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
typedef MTLTriangleTessellationFactorsHalf PatchTessFactors;
#endif
kernel void compute_main(
const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
unsigned thread_position_in_grid [[thread_position_in_grid]],
unsigned thread_position_in_threadgroup [[thread_position_in_threadgroup]],
unsigned threadgroup_position_in_grid [[threadgroup_position_in_grid]],
OsdPatchParamBufferSet osdBuffers,
device MTLQuadTessellationFactorsHalf* quadTessellationFactors [[buffer(QUAD_TESSFACTORS_INDEX)]]
device PatchTessFactors* patchTessellationFactors [[buffer(PATCH_TESSFACTORS_INDEX)]]
#if OSD_USE_PATCH_INDEX_BUFFER
,device unsigned* patchIndex [[buffer(OSD_PATCH_INDEX_BUFFER_INDEX)]]
,device MTLDrawPatchIndirectArguments* drawIndirectCommands [[buffer(OSD_DRAWINDIRECT_BUFFER_INDEX)]]
#endif
)
{
//----------------------------------------------------------
// OSD Kernel Setup
//----------------------------------------------------------
#define PATCHES_PER_THREADGROUP (THREADS_PER_THREADGROUP / THREADS_PER_PATCH)
int const primitiveID = thread_position_in_grid / THREADS_PER_PATCH;
int const primitiveIDInTG = thread_position_in_threadgroup / THREADS_PER_PATCH;
int const vertexIndex = threadgroup_position_in_grid * PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH +
thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
int const vertexIndexInTG = thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
int const invocationID = (thread_position_in_threadgroup * VERTEX_CONTROL_POINTS_PER_THREAD) % (THREADS_PER_PATCH*VERTEX_CONTROL_POINTS_PER_THREAD);
//Contains the shared patchParam value used by all threads that act upon a single patch
//the .z (sharpness) field is set to -1 (NAN) if that patch should be culled to signal other threads to return.
threadgroup int3 patchParam[PATCHES_PER_THREADGROUP];
threadgroup PatchVertexType patchVertices[PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH];
const auto real_threadgroup = thread_position_in_grid / REAL_THREADGROUP_DIVISOR;
const auto subthreadgroup_in_threadgroup = thread_position_in_threadgroup / REAL_THREADGROUP_DIVISOR;
const auto real_thread_in_threadgroup = thread_position_in_threadgroup & (REAL_THREADGROUP_DIVISOR - 1);
#if NEEDS_BARRIER
const auto validThread = thread_position_in_grid * CONTROL_POINTS_PER_THREAD < osdBuffers.kernelExecutionLimit;
#else
const auto validThread = true;
if(thread_position_in_grid * CONTROL_POINTS_PER_THREAD >= osdBuffers.kernelExecutionLimit)
return;
#endif
if(validThread)
//----------------------------------------------------------
// OSD Vertex Transform
//----------------------------------------------------------
{
patchParam[subthreadgroup_in_threadgroup] = OsdGetPatchParam(real_threadgroup, osdBuffers.patchParamBuffer);
patchParam[primitiveIDInTG] = OsdGetPatchParam(primitiveID, osdBuffers.patchParamBuffer);
for(unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; threadOffset++)
for (unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; ++threadOffset)
{
const auto vertexId = osdBuffers.indexBuffer[(thread_position_in_grid * CONTROL_POINTS_PER_THREAD + threadOffset) * IndexLookupStride];
const auto v = osdBuffers.vertexBuffer[vertexId];
if (vertexIndexInTG + threadOffset < PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH)
{
const auto vertexId = osdBuffers.indexBuffer[(vertexIndex + threadOffset)];
const auto v = osdBuffers.vertexBuffer[vertexId];
threadgroup auto& patchVertex = patchVertices[thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD + threadOffset];
OsdComputePerVertex(float4(v.position,1), patchVertex, vertexId, frameConsts.ModelViewProjectionMatrix, osdBuffers);
//User per vertex goes here, modifying 'patchVertex'
threadgroup auto& patchVertex = patchVertices[vertexIndexInTG + threadOffset];
//----------------------------------------------------------
// User Vertex Transform
//----------------------------------------------------------
OsdComputePerVertex(float4(v.position,1), patchVertex, vertexId, frameConsts.ModelViewProjectionMatrix, osdBuffers);
}
}
}
@ -349,27 +356,31 @@ kernel void compute_main(
threadgroup_barrier(mem_flags::mem_threadgroup);
#endif
if(validThread)
//----------------------------------------------------------
// OSD Patch Cull
//----------------------------------------------------------
{
#if PATCHES_PER_THREADGROUP > 1
auto patch = patchVertices + subthreadgroup_in_threadgroup * CONTROL_POINTS_PER_THREAD * CONTROL_POINTS_PER_PATCH;
#else
//Small optimization for the '1 patch per threadgroup' case
auto patch = patchVertices;
#endif
auto patch = patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH;
if(!OsdCullPerPatchVertex(patch, frameConsts.ModelViewMatrix))
if (!OsdCullPerPatchVertex(patch, frameConsts.ModelViewMatrix))
{
#if !OSD_USE_PATCH_INDEX_BUFFER
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[0] = 0.0h;
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[1] = 0.0h;
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[2] = 0.0h;
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[3] = 0.0h;
quadTessellationFactors[real_threadgroup].insideTessellationFactor[0] = 0.0h;
quadTessellationFactors[real_threadgroup].insideTessellationFactor[1] = 0.0h;
#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[3] = 0.0h;
patchTessellationFactors[primitiveID].insideTessellationFactor[0] = 0.0h;
patchTessellationFactors[primitiveID].insideTessellationFactor[1] = 0.0h;
#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
patchTessellationFactors[primitiveID].insideTessellationFactor = 0.0h;
#endif
#endif
patchParam[subthreadgroup_in_threadgroup].z = -1;
patchParam[primitiveIDInTG].z = -1;
#if !NEEDS_BARRIER
return;
#endif
@ -380,18 +391,24 @@ kernel void compute_main(
threadgroup_barrier(mem_flags::mem_threadgroup);
#endif
if(validThread && patchParam[subthreadgroup_in_threadgroup].z != -1)
//----------------------------------------------------------
// OSD Patch Compute
//----------------------------------------------------------
if (patchParam[primitiveIDInTG].z != -1)
{
for(unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; threadOffset++)
for (unsigned threadOffset = 0; threadOffset < VERTEX_CONTROL_POINTS_PER_THREAD; ++threadOffset)
{
OsdComputePerPatchVertex(
patchParam[subthreadgroup_in_threadgroup],
real_thread_in_threadgroup * CONTROL_POINTS_PER_THREAD + threadOffset,
real_threadgroup,
thread_position_in_grid * CONTROL_POINTS_PER_THREAD + threadOffset,
patchVertices + subthreadgroup_in_threadgroup * CONTROL_POINTS_PER_PATCH,
osdBuffers
);
if (invocationID + threadOffset < VERTEX_CONTROL_POINTS_PER_PATCH)
{
OsdComputePerPatchVertex(
patchParam[primitiveIDInTG],
invocationID + threadOffset,
primitiveID,
invocationID + threadOffset + primitiveID * VERTEX_CONTROL_POINTS_PER_PATCH,
patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
osdBuffers
);
}
}
}
@ -399,26 +416,29 @@ kernel void compute_main(
threadgroup_barrier(mem_flags::mem_device_and_threadgroup);
#endif
if(validThread && real_thread_in_threadgroup == 0)
//----------------------------------------------------------
// OSD Tessellation Factors
//----------------------------------------------------------
if (invocationID == 0)
{
#if OSD_USE_PATCH_INDEX_BUFFER
const auto patchId = atomic_fetch_add_explicit((device atomic_uint*)&drawIndirectCommands->patchCount, 1, memory_order_relaxed);
patchIndex[patchId] = real_threadgroup;
patchIndex[patchId] = primitiveID;
#else
const auto patchId = real_threadgroup;
const auto patchId = primitiveID;
#endif
OsdComputePerPatchFactors(
patchParam[subthreadgroup_in_threadgroup],
patchParam[primitiveIDInTG],
frameConsts.TessLevel,
real_threadgroup,
primitiveID,
frameConsts.ProjectionMatrix,
frameConsts.ModelViewMatrix,
osdBuffers,
patchVertices + subthreadgroup_in_threadgroup * CONTROL_POINTS_PER_PATCH,
quadTessellationFactors[patchId]
);
patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
patchTessellationFactors[patchId]
);
}
}
@ -607,14 +627,14 @@ fragment float4 fragment_main(
float3 normal = perturbNormalFromDisplacement(input.position.xyz,
input.normal,
input.patchCoord,
config.mipmapBias,
mipmapBias,
textureDisplace_Data,
textureDisplace_Packing,
config.displacementScale);
displacementScale);
#elif NORMAL_BIQUADRATIC || NORMAL_BIQUADRATIC_WG
float4 du, dv;
float4 disp = PtexMipmapLookupQuadratic(du, dv, input.patchCoord,
config.mipmapBias,
mipmapBias,
textureDisplace_Data,
textureDisplace_Packing);
@ -655,15 +675,15 @@ fragment float4 fragment_main(
textureImage_Packing);
#elif COLOR_PATCHTYPE
float4 texColor = lighting(float4(input.patchColor), input.position.xyz, normal, 0, lightSource);
outColor = texColor;
outColor = max(texColor, shade);
return outColor;
#elif COLOR_PATCHCOORD
float4 texColor = lighting(input.patchCoord, input.position.xyz, normal, 0, lightSource);
outColor = texColor;
outColor = max(texColor, shade);
return outColor;
#elif COLOR_NORMAL
float4 texColor = float4(normal.x, normal.y, normal.z, 1);
outColor = texColor;
outColor = max(texColor, shade);
return outColor;
#else // COLOR_NONE
float4 texColor = float4(0.5, 0.5, 0.5, 1);
@ -672,7 +692,7 @@ fragment float4 fragment_main(
// ------------ occlusion ---------------
#if USE_PTEX_OCCLUSION
float occ = PtexMipmapLookup(input.patchCoord, config.mipmapBias,
float occ = PtexMipmapLookup(input.patchCoord, mipmapBias,
textureOcclusion_Data,
textureOcclusion_Packing).x;
#else
@ -682,7 +702,7 @@ fragment float4 fragment_main(
// ------------ specular ---------------
#if USE_PTEX_SPECULAR
float specular = PtexMipmapLookup(input.patchCoord, config.mipmapBias,
float specular = PtexMipmapLookup(input.patchCoord, mipmapBias,
textureSpecular_Data,
textureSpecular_Packing).x;
#else

File diff suppressed because it is too large Load Diff