1

Прежде чем вдаваться в подробности, я хочу наметить проблему:Как я могу передать результаты вычисления шейдера в вершинный шейдер без использования буфера вершин?

Я использую RWStructuredBuffers для хранения выходных данных моих вычислительных шейдеров (CS). Так как вершинные и пиксельные шейдеры не могут считывать данные из RWStructuredBuffers, я сопоставить StructuredBuffer на тот же временный интервал (U0/t0) и (U4/t4):

cbuffer cbWorld : register (b1) 
{ 
    float4x4 worldViewProj; 
    int dummy; 
} 

struct VS_IN 
{ 
    float4 pos : POSITION; 
    float4 col : COLOR; 
}; 

struct PS_IN 
{ 

    float4 pos : SV_POSITION; 
    float4 col : COLOR; 
}; 

RWStructuredBuffer<float4> colorOutputTable : register (u0); // 2D color data 
StructuredBuffer<float4> output2 :   register (t0); // same as u0 
RWStructuredBuffer<int> counterTable :  register (u1); // depth data for z values 
RWStructuredBuffer<VS_IN>vertexTable :  register (u4); // triangle list 
StructuredBuffer<VS_IN>vertexTable2 :   register (t4); // same as u4 

я использую ShaderRecourceView предоставлять пиксель и/или вершину шейдерный доступ к буферам. Эта концепция отлично работает для моих пиксельных шейдеров, вершинные шейдеры, однако, кажется, не только для чтения 0 значения (я использую SV_VertexID как индекс для буферов):

PS_IN VS_3DA (uint vid : SV_VertexID) 
{   
    PS_IN output = (PS_IN)0; 
    PS_IN input = vertexTable2[vid]; 
    output.pos = mul(input.pos, worldViewProj); 
    output.col = input.col; 
    return output; 
} 

Нет сообщений об ошибках или предупреждений от HLSL компилятора, запускается renderloop с 60 fps (используя vsync), но экран остается черным. Так как я пустую экран с Color.White до вызова Draw (..), конвейер визуализации, кажется, активен.

Когда я прочитал содержание треугольника данных через UAView из ГПУ в «vertArray» и кормить его обратно в буфер вершин, все работает, однако:

Программа:

let vertices = Buffer.Create(device, BindFlags.VertexBuffer, vertArray) 
    context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0)) 

HLSL:

PS_IN VS_3D (VS_IN input) 
{ 
    PS_IN output = (PS_IN)0;  
    output.pos = mul(input.pos, worldViewProj); 
    output.col = input.col; 
    return output; 
} 

Здесь определено определение 2D-вершин/пикселов. Обратите внимание, что PS_2D доступа к буферам «output2» в слоте t0 - и это именно «трюк», что я хочу повторить для того 3D вершинного шейдера «VS_3DA»:

float4 PS_2D (float4 input : SV_Position) : SV_Target 
{   
    uint2 pixel = uint2(input.x, input.y);   
    return output2[ pixel.y * width + pixel.x]; 
} 

float4 VS_2D (uint vid : SV_VertexID) : SV_POSITION 
{ 
if (vid == 0) 
    return float4(-1, -1, 0, 1); 
if (vid == 1) 
    return float4(1, -1, 0, 1); 
if (vid == 2) 
    return float4(-1, 1, 0, 1);  

return float4(1, 1, 0, 1);  
} 

За три дня я искал и экспериментировал но безрезультатно. Вся информация, которую я собрал, кажется, подтверждает, что мой подход с использованием SV_VertexID должен работать.

Можно ли дать совет? Спасибо, что прочитали мой пост!

==================================================================================================================================== =======================

ДЕТАЛИ:

Мне нравится концепция DirectX 11 вычислительными шейдерами очень много, и я хочу, чтобы использовать его для алгебраических вычислений. В качестве тестового примера я делаю фракталы (наборы Мандельброта) в 3D. Все работает так, как ожидалось, - кроме одного последнего кирпича в стене отсутствует.

Вычисление принимает следующие шаги:

  1. с использованием CS для вычисления 2D текстуры (выход «counterTable» и «colorOutbutTable» (работы)

  2. Необязательно вынести эту текстуру на экран (работ)

  3. Использование другой CS для создания сетки (список треугольников). Эта CS принимает значения x, y и цвета с шага 1, вычисляет координату z и, наконец, создает квадрат для каждого пикселя. хранится ed в "vertexTable". (работы)

  4. Подача списка треугольников вершинному шейдеру (проблема !!!)

  5. Render to screen (работает - используя буфер вершин).

Для программирования я использую F # 3.0 и SharpDX как .NET-оболочку. ShaderRessourceView для обоих шейдеров (пиксельных & вершина) устанавливается с теми же параметрами (за исключением параметров размера):

let mutable descr = new BufferDescription()  
descr.BindFlags <- BindFlags.UnorderedAccess ||| BindFlags.ShaderResource 
descr.Usage <- ResourceUsage.Default 
descr.CpuAccessFlags <- CpuAccessFlags.None 
descr.StructureByteStride <- xxx // depends on shader 
descr.SizeInBytes <- yyy  // depends on shader 
descr.OptionFlags <- ResourceOptionFlags.BufferStructured 

Ничего особенного здесь. Создание 2D-буфера (связывается с буфером "output2" в слот-t0):

outputBuffer2D <- new Buffer(device, descr) 
outputView2D <- new UnorderedAccessView (device, outputBuffer2D) 
shaderResourceView2D <- new ShaderResourceView (device, outputBuffer2D) 

Создание 3D-буфера (связывается с "vertexTable2" в слот-t4):

vertexBuffer3D <- new Buffer(device, descr) 
shaderResourceView3D <- new ShaderResourceView (device, vertexBuffer3D) 
// UAView not required here 

Настройка ресурсов для 2D :

context.InputAssembler.PrimitiveTopology <- PrimitiveTopology.TriangleStrip 
context.OutputMerger.SetRenderTargets(renderTargetView2D) 
context.OutputMerger.SetDepthStencilState(depthStencilState2D) 
context.VertexShader.Set (vertexShader2D) 
context.PixelShader.Set (pixelShader2D) 

визуализации 2D:

context.PixelShader.SetShaderResource(COLOR_OUT_SLOT, shaderResourceView2D) 
context.PixelShader.SetConstantBuffer(CONSTANT_SLOT_GLOBAL, constantBuffer2D) 
context.ClearRenderTargetView (renderTargetView2D, Color.White.ToColor4())   
context.Draw(4,0)             
swapChain.Present(1, PresentFlags.None)    

Настройка ресурсов для 3D:

context.InputAssembler.PrimitiveTopology <- PrimitiveTopology.TriangleList 
context.OutputMerger.SetTargets(depthView3D, renderTargetView2D) 
context.VertexShader.SetShaderResource(TRIANGLE_SLOT, shaderResourceView3D) 
context.VertexShader.SetConstantBuffer(CONSTANT_SLOT_3D, constantBuffer3D) 
context.VertexShader.Set(vertexShader3D) 
context.PixelShader.Set(pixelShader3D) 

рендеринга 3D (не работает - черный экран в качестве выходного результата)

context.ClearDepthStencilView(depthView3D, DepthStencilClearFlags.Depth, 1.0f, 0uy) 
context.Draw(dataXsize * dataYsize * 6, 0) 
swapChain.Present(1, PresentFlags.None) 

Наконец игровые номера:

static let CONSTANT_SLOT_GLOBAL = 0 
static let CONSTANT_SLOT_3D = 1 
static let COLOR_OUT_SLOT = 0 
static let COUNTER_SLOT = 1 
static let COLOR_SLOT = 2  
static let TRIANGLE_SLOT = 4 
+0

Вы когда-нибудь исправляли это? Я ищу, чтобы сделать почти то же самое, но это не работает для меня. Как вы это исправили? – Miguel

ответ

1

Ok первое Я бы предположил, что нужно включить слой отладки (использовать флаг Debug при создании вашего устройства), затем перейти к свойствам проекта, вкладке отладки и поставить галочку «Включить неуправляемую отладку кода» или «Включить отладку собственного кода».

Когда вы начинаете отлаживать программу, время выполнения даст вам потенциальные предупреждения, если что-то не так с конвейерным состоянием.

Один потенциальный вопрос (который выглядит наиболее вероятным из того, что вы опубликовали): Обязательно очистите свои слоты БПЛА с помощью вычислительного шейдера после отправки. Если вы попытаетесь связать vertexTable2 с вашим вершинным шейдером, но ресурс по-прежнему привязан к выходу вычислительного шейдера, среда выполнения автоматически установит ваш ShaderView в null (который, в свою очередь, вернет 0 при попытке прочитать его).

Чтобы очистить Compute Shader, вызовите это на вы сделали с отправкой контекста устройства одно:

ComputeShader.SetUnorderedAccessView(TRIANGLE_SLOT, null) 

Пожалуйста, обратите внимание, что PixelShader доступ RWStructuredBuffer (технически вы можете использовать RWStructuredBuffer для любого типа шейдера, если у вас есть уровень 11.1, это означает недавнюю карту ATI и Windows 8+).

+0

Я использую 4 вычислительных шейдера, и после каждого диспетчерского вызова я очищаю все ресурсы, поэтому ваше предложение уже содержится в коде. брошенный). –

+0

В настоящее время я использую VS Express для веб-сайта 2012 (поскольку включен F # 3.0); параметры отладки, которые вы описываете, не существует на моей вкладке свойств отладки (только «включить процесс хостинга VS»). Я предполагаю, что мне нужно использовать полную версию VS для получения отладки DirectX (когда я создаю swapchain с опцией debug, генерируется исключение). Поэтому у меня нет шансов на отладку низкого уровня на данный момент. Если вы знаете веб-ресурс, в котором объясняется, как включить отладку DirectX в Visual Studio, я был бы рад получить его. –

+0

SharpDX использует разные библиотеки для каждого уровня DirectX, поэтому я придерживаюсь 11.0, чтобы быть обратно совместимым с некоторыми друзьями. –

0

Feeding список треугольников в вершинном шейдере (проблема !!!)

Вместо использования структурированных буферов (которые не позволяют связывать как VB), я хотел бы посмотреть в использование сырой буферы. Он требует кастинга в шейдере, но позволяет использовать тот же буфер в ваших cs и vs.

При создании буфера, сделайте следующее:

D3D11_BUFFER_DESC desc = {}; 
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_VERTEX_BUFFER; 
desc.ByteWidth = byteSize; 
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; 

Затем можно связать как шейдерного ресурса:

D3D11_SHADER_RESOURCE_VIEW_DESC desc = {}; 
desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; 
desc.BufferEx.FirstElement = 0; 
desc.Format = DXGI_FORMAT_R32_TYPELESS; 
desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; 
desc.BufferEx.NumElements = descBuf.ByteWidth/4; 

или Unordered Access View:

D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {}; 
desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; 
desc.Buffer.FirstElement = 0; 
desc.Format = DXGI_FORMAT_R32_TYPELESS; // Format must be DXGI_FORMAT_R32_TYPELESS, when creating Raw Unordered Access View 
desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; 
desc.Buffer.NumElements = descBuf.ByteWidth/4; 

В шейдере вы будет использовать примерно следующее:

ByteAddressBuffer Buffer0 : register(t0); 
ByteAddressBuffer Buffer1 : register(t1); 
RWByteAddressBuffer BufferOut : register(u0); 

int i0 = asint(Buffer0.Load(DTid.x*8)); 
float f0 = asfloat(Buffer0.Load(DTid.x*8+4)); 
int i1 = asint(Buffer1.Load(DTid.x*8)); 
float f1 = asfloat(Buffer1.Load(DTid.x*8+4)); 

BufferOut.Store(DTid.x*8, asuint(i0 + i1)); 
BufferOut.Store(DTid.x*8+4, asuint(f0 + f1)); 

Пример кода, приведенного выше, был взят из образца BasicCompute11 из SDK DirectX June 2010. Он демонстрирует использование как структурированных буферов, так и необработанных буферов.