ডাইরেক্টএক্স 11, কীভাবে আমি একাধিক শেডার ধ্রুবক বাফার পরিচালনা করব এবং আপডেট করব?


13

ঠিক আছে, ধ্রুবক বাফারগুলি কীভাবে পাইপলাইন পর্যায়ে আবদ্ধ এবং আপডেট হয় তা উপলব্ধি করতে আমার বেশ কষ্ট হচ্ছে। আমি বুঝেছি যে ডাইরেক্টএক্স 11 -এর পর্যায়ে 15 পর্যন্ত শেডার-ধ্রুবক বাফার থাকতে পারে এবং প্রতিটি বাফার 4096 ধাপে ধাপে ধরে রাখতে পারে। তবে, আমি বুঝতে পারছি না যে আইডি 3 ডি 11 বাফার সিওএম ধ্রুবক বাফারের সাথে ইন্টারেক্ট করার জন্য ব্যবহৃত হয়েছিল তা এই বাফার স্লটগুলি পূরণ করার জন্য ব্যবহৃত একটি প্রক্রিয়া (বা হ্যান্ডেল) বা যদি বস্তুটি আসলে বাফার ডেটার একটি নির্দিষ্ট উদাহরণকে উল্লেখ করে যা সামনে এবং পিছনে ঠেলা যায় is জিপিইউ এবং সিপিইউ এর মধ্যে।

আমি মনে করি বিষয়টিতে আমার বিভ্রান্তি একটি সমস্যার কারণ যা আমি দুটি ভিন্ন ধ্রুবক বাফার ব্যবহার করছি।

এখানে কিছু উদাহরণ শ্যাডার কোড রয়েছে is

cbuffer PerFrame : register(b0) {
    float4x4 view;
};

cbuffer PerObject : register(b1) {
    float4x4 scale;
    float4x4 rotation;
    float4x4 translation;
};

আমার কোডটি যেভাবে সংগঠিত হয়েছে, ক্যামেরাটি প্রতি ফ্রেম ডেটা সম্পর্কিত প্রাসঙ্গিক আপডেটটি পরিচালনা করবে এবং গেমঅবজেক্টস তাদের নিজস্ব প্রতি বস্তুর ডেটা আপডেট করবে। উভয় শ্রেণীর নিজস্ব আইডি 3 ডি 11 বাফার রয়েছে যা এটি করতে ব্যবহৃত হয় (একটি হাব আর্কিটেকচার ব্যবহার করে, সুতরাং একটি গেমঅজেক্ট ক্লাস বিশ্বের সমস্ত ইনস্টল করা গেমঅবজেক্টের রেন্ডারিং পরিচালনা করবে)।

সমস্যাটি হ'ল আমি স্লটের উপর নির্ভর করে কেবল একবারে একটি আপডেট করতে পারি এবং আমি অনুমান করি যে আপডেটের ক্রমটি একটি বাফার পূরণ হয়ে যায় এবং অন্যটি শূন্য হয়ে যায়।

এটি মূলত আমার কোড। উভয় শ্রেণিতে অভিন্ন আপডেট যুক্তি ব্যবহার করা হয়।

static PerObjectShaderBuffer _updatedBuffer; // PerFrameShaderBuffer if Camera class
_updatedBuffer.scale       = _rScale;
_updatedBuffer.rotation    = _rRotation;
_updatedBuffer.translation = _rTranslation;
pDeviceContext->UpdateSubresource(pShaderBuffer, 0 , 0, &_updatedBuffer, 0, 0);

pDeviceContext->VSSetShader(pVShader->GetShaderPtr(), 0, 0);
pDeviceContext->PSSetShader(pPShader->GetShaderPtr(), 0, 0);
pDeviceContext->VSSetConstantBuffers(1, 1, &pShaderBuffer);
pDeviceContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &vStride, &_offset );
pDeviceContext->IASetPrimitiveTopology(topologyType);
pDeviceContext->Draw(bufSize, 0);

আমার প্রধান প্রশ্নগুলি হ'ল -

  • আপডেটসুব্রোসোর্স কল দিয়ে আপডেট করার জন্য আমার কি শেডারবাফার সেট বা বাঁধাই করা দরকার? (অর্থ যখন পাইপলাইনে থাকবে তখনই এটি হেরফের করবে) বা এটি কোনও ডেটা ব্লব যা ভিএসসেট কনস্ট্যান্টবাফার কল দিয়ে প্রেরণ করা হবে? (অর্থ ডেটা বাঁধাই ও আপডেট করার ক্রমের অর্থ হয় না, আমি পাইপলাইনে এটি আপডেট করতে পারি বা কোনওভাবে সিপিইউতে)
  • বাফার সেট বা বাঁধাইয়ের সময়, পেরফ্রেম বাফার আপডেট করার জন্য আমার কি স্লট 0 রেফারেন্স করা দরকার এবং পেরোবজেক্ট বাফারটি আপডেট করার জন্য স্লট 1? আমার কোডে এই কলটির সাথে কোনও ধরণের বিভ্রান্তি কি সমস্ত বাফারগুলিকে ওভাররাইট করার কারণ হতে পারে?
  • ডি 3 ডি 11 কীভাবে জানবে যে আমি আপডেট করতে বা মানচিত্রটি করতে চাই? এটি ID3D11Buffer COM ব্যবহৃত থেকে জানতে পারে?

সম্পাদনা করুন -

উপরের উদাহরণে ধ্রুব বাফার রেজিস্টার ট্যাগগুলি পরিবর্তন করা হয়েছে। (খ #) এর পরিবর্তে (সিবি #) ব্যবহার করা বাফারকে কোনও কারণে সঠিকভাবে আপডেট হতে প্রভাবিত করছে। আমি আসল সিনট্যাক্সটি কোথায় নিয়েছি বা এটি আদৌ বৈধ কিনা তা নিশ্চিত নয় তবে এটি আমার মূল সমস্যা বলে মনে হয়।

উত্তর:


18

আইডি 3 ডি 11 বাফার মেমরির একটি প্রকৃত অংশের উল্লেখ করে যা আপনার ডেটা ধারণ করে, এটি কোনও ভার্টেক্স বাফার, ধ্রুবক বাফার বা যাই হোক না কেন।

কনস্ট্যান্ট বাফার্স একইভাবে কাজ করে যেমন ভার্টেক্স বাফার এবং অন্যান্য ধরণের বাফার। যথা, এগুলিতে থাকা ডেটা জিপিইউ দ্বারা অ্যাক্সেস করা হয় না যতক্ষণ না এটি প্রকৃতপক্ষে ফ্রেমটি সরবরাহ করে, সুতরাং জিপিইউটি সম্পন্ন না করা পর্যন্ত বাফারকে বৈধ থাকতে হবে। আপনার প্রতিটি ধ্রুবক বাফারটি ডাবল-বাফার করা উচিত, সুতরাং আপনার পরবর্তী ফ্রেমের জন্য আপডেট করার জন্য একটি কপি এবং বর্তমান ফ্রেমটি রেন্ডার করার সময় জিপিইউ পড়ার জন্য একটি কপি থাকতে হবে। আপনি কীভাবে কোনও কণা সিস্টেম বা অনুরূপের জন্য ডায়নামিক ভারটেক্স বাফার করবেন তা এটি সমান।

register(cb0), register(cb1)VSSetConstantBuffers মধ্যে স্লট সঙ্গে HLSL মিলা সেটিংস। আপনি যখন প্রতি-ফ্রেম ধ্রুবকগুলি VSSetConstantBuffers(0, 1, &pBuffer)আপডেট করেন আপনি VSSetConstantBuffers(1, 1, &pBuffer)সিবি0 সেট করতে এবং যখন আপনি প্রতি-বস্তুটি আপডেট করেন আপনি সিবি 1 সেট করতে চান । প্রতিটি কল কেবলমাত্র শুরু / গণনা প্যারামিটার দ্বারা উল্লিখিত বাফারগুলিকে আপডেট করে এবং অন্যকে স্পর্শ করে না।

আপডেটসুব্রোসোর্স দিয়ে আপডেট করার জন্য আপনাকে বাফারকে আবদ্ধ করার দরকার নেই। আসলে, আপনি এটি আপডেট করার সময় এটি আবদ্ধ হওয়া উচিত নয় , বা এটি অভ্যন্তরীণভাবে ড্রাইভারটিকে অতিরিক্ত মেমরির অনুলিপিগুলি তৈরি করতে বাধ্য করতে পারে ( আপডেটসুব্রোসোর্সোসার জন্য এমএসডিএন পৃষ্ঠা দেখুন , বিশেষত একটি পৃষ্ঠা সম্পর্কে বিতর্ক সম্পর্কে মন্তব্য)।

আমি নিশ্চিত নই যে আপনি "D3D11 কীভাবে জানেন যে আমি কোন বাফারটি আপডেট করতে বা মানচিত্র করতে চাই?" এটি যার পয়েন্টার আপনি পাস করেছেন তাকে আপডেট করে বা মানচিত্র করে।


3

ধ্রুব বাফারগুলি আপডেট করার পরে পুনরায় বাঁধাই করা দরকার এমন বিষয়টিকে ঘিরে অনেকগুলি বিভ্রান্তি রয়েছে বলে মনে হচ্ছে। আমি নিজেই এ সম্পর্কে শিখছি বলে আমি এর বিপরীতে মতামত নিয়ে অনেকগুলি বিষয় এবং আলোচনা দেখেছি। এখানে সেরা উত্তর, XXSetConstantBuffersআপনি UpdateSubresourceবা মাধ্যমে আপডেট করার পরে কল করার পরামর্শ দিচ্ছেন Map/Unmap

এছাড়াও, কিছু ডি 3 ডি এমএসডিএন নমুনা এবং ডকুমেন্টেশন এই প্যাটার্নটি ব্যবহার করছে বলে মনে হচ্ছে, প্রতি ফ্রেমে বা এমনকি আঁকানো-অবজেক্ট ভিত্তিতে বাঁধাই (কলিং XXSetConstantBuffers) করা হচ্ছে, যদিও তারা কেবলমাত্র একটি বিদ্যমান বাফার আপডেট করে এবং সম্পূর্ণ আলাদা বাফারের সাথে একটি নির্দিষ্ট স্লট পরিবর্তন করে না ।

আমি মনে করি সবচেয়ে খারাপ ধারণাটি হ'ল XXSetConstantBuffers"আপনার পূর্বে আপডেট হওয়া ডেটা জিপিইউতে প্রেরণ করে বা আপডেটটি অবহিত করে, যাতে এটি নতুন মানগুলি গ্রহণ করে - যা পুরোপুরি ভুল বলে মনে হয়।

প্রকৃতপক্ষে, ব্যবহার করার সময় UpdateSubresourceবা Map/Unmapডকুমেন্টেশনে বলা হয়েছে যে জিপিইউটির এখনও পুরানো ডেটার প্রয়োজন হলে অভ্যন্তরীণভাবে একাধিক অনুলিপি তৈরি করা যেতে পারে, তবে এটি ইতিমধ্যে আবদ্ধ বাফারটি আপডেট করার ক্ষেত্রে এপিআই-র ব্যবহারকারীর পক্ষে উদ্বেগ নয়। সুতরাং সুস্পষ্টভাবে আনবাউন্ডের প্রয়োজন অতিমাত্রায় মনে হয়।

আমার পরীক্ষার সময়, আমি এই সিদ্ধান্তে পৌঁছেছি যে বাফারগুলি XXSetConstantBuffersইতিমধ্যে আবদ্ধ না করে তাদের আপডেট করার পরে পুনরায় বাঁধাই করা অপ্রয়োজনীয় ! যতক্ষণ আপনি একই বাফারগুলি ব্যবহার করেন (শেডারগুলির মধ্যে ভাগ করে নেওয়া, সন্ধ্যাকালীন পাইপলাইন স্তরগুলি) যা একবার আবদ্ধ (উদাহরণস্বরূপ, প্রারম্ভের পর্যায়ে) আপনাকে এগুলি পুনরায় আবদ্ধ করতে হবে না - কেবল আপডেট করুন।

আমার পরীক্ষাগুলি প্রকৃতির আরও ভালভাবে প্রদর্শন করার জন্য কিছু কোড:

// Memory double of the buffer (static)
ConstBuffer* ShaderBase::CBuffer = (ConstBuffer*)_aligned_malloc(sizeof(ConstBuffer), 16);
// Hardware resource pointer (static)
ID3D11Buffer* ShaderBase::m_HwBuffer = nullptr;

void ShaderBase::Buffer_init()
{
     // Prepare buffer description etc.
     // Create one global buffer shared across shaders
     result = device->CreateBuffer(&cBufferDesc, NULL, &m_HwBuffer);
     BindConstBuffer();
}

...

void ShaderBase::BindConstBuffer()
{
     // Bind buffer to both VS and PS stages since it's a big global one
     deviceContext->VSSetConstantBuffers(0, 1, &m_HwBuffer);
     deviceContext->PSSetConstantBuffers(0, 1, &m_HwBuffer);
}

...
bool ShaderBase::UpdateConstBuffers()
{
    ...
    D3D11_MAPPED_SUBRESOURCE mappedResource;

    // Lock the constant buffer so it can be written to.
    deviceContext->Map(m_HwBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);

    // Get a pointer to the data in the constant buffer.
    ConstBuffer* dataPtr = (ConstBuffer*)mappedResource.pData;
    memcpy(dataPtr, CBuffer, sizeof(ConstBuffer));

    // Unlock the constant buffer.
    deviceContext->Unmap(m_HwBuffer, 0);
    return true;
}

// May be called multiple times per frame (multiple render passes)
void DrawObjects()
{
    // Simplified version
    for each Mesh _m to be drawn
    {
        // Some changes are per frame - but since we have only one global buffer to which we 
        // write with write-discard we need to set all of the values again when we update per-object
        ShaderBase::CBuffer->view = view;
        ShaderBase::CBuffer->projection = projection;
        ShaderBase::CBuffer->cameraPosition = m_Camera->GetPosition();

        ... 

        ShaderBase::CBuffer->lightDirection = m_Light->GetDirection();

        ShaderBase::CBuffer->lightView = lightView;
        ShaderBase::CBuffer->lightProjection = lightProjection;
        ShaderBase::CBuffer->world = worldTransform;

        // Only update! No rebind!
        if (ShaderBase::UpdateConstBuffers() == false)
            return false;

        _m->LoadIABuffers(); // Set the vertex and index buffers for the mesh
        deviceContext->DrawIndexed(_m->indexCount, 0, 0);
    }
}

এখানে ইন্টারনেট (গেমদেব ফোরাম) থেকে কিছু বিষয় রয়েছে যা এই পদ্ধতির অবলম্বন করে এবং এটির প্রস্তাব দেয় বলে মনে হয়: http://www.gamedev.net/topic/649410-set-constant-buffers-every-frame/?view=findpost&p=5105032 এবং http://www.gamedev.net/topic/647203-updating-constant-buffers/#entry5090000

সঙ্কোচনের জন্য, এটি সত্যিই মনে হয় যে আপনি বাফার পুরোপুরি পরিবর্তন না করে বাঁধাইয়ের প্রয়োজন নেই তবে যতক্ষণ না আপনি বাফারগুলি ভাগ করুন এবং শেডারগুলির মধ্যে তাদের লেআউট (প্রস্তাবিত অনুশীলন) বাঁধাই করা উচিত এই ক্ষেত্রে:

  • শুরুতে - প্রাথমিক বাঁধাই - উদাহরণস্বরূপ বাফার তৈরির পরে after
  • আপনার যদি প্রয়োজন হয় / এক বা একাধিক পর্যায়ের নির্দিষ্ট স্লটে আবদ্ধ একাধিক বাফার ব্যবহার করতে ডিজাইন করেছেন।
  • ডিভাইস কনটেক্সট এর অবস্থা সাফ করার পরে (যখন বাফার / উইন্ডোজের আকার পরিবর্তন করা হয়)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.