Översikt över lager
Den här översikten beskriver grunderna i att använda Direct2D-lager. Den innehåller följande avsnitt.
- Vad är lager?
- lager i Windows 8 och senare
- Att skapa lager
- innehållsgräns
- geometriska masker
- Opacitetsmasker
- Alternativ till lager
- Klipp ut en godtycklig form
- Relaterade ämnen
Vad är lager?
Lager, som representeras av ID2D1Layer objekt, gör det möjligt för ett program att manipulera en grupp med ritningsåtgärder. Du använder ett lager genom att "push-överföra" det till ett återgivningsmål. Efterföljande ritoperationer från återgivningsmålet riktas mot lagret. När du är klar med lagret ploppar du lagret från återgivningsmålet, vilket sammansätter lagrets innehåll tillbaka till återgivningsmålet.
Precis som penslar är lager resurser som är beroende av enheten och skapas av renderingsmål. Lager kan användas på alla återgivningsmål i samma resursdomän som innehåller återgivningsmålet som skapade det. En lagerresurs kan dock bara användas av ett återgivningsmål i taget. För mer information om resurser, se Resursöversikt.
Även om skikt erbjuder en kraftfull återgivningsteknik för att producera intressanta effekter, kan ett stort antal lager i ett program påverka dess prestanda negativt på grund av de olika kostnaderna för att hantera lager och lagerresurser. Det finns till exempel kostnaden för att fylla eller rensa lagret och sedan blanda tillbaka det, särskilt på avancerad maskinvara. Sedan har vi kostnaden för att hantera lagerresurserna. Om du omallokerar dessa ofta, blir prestandaproblemen med GPU:n det mesta betydande problemet. När du utformar ditt program kan du försöka maximera återanvändning av lagerresurser.
Lager i Windows 8 och senare
Windows 8 introducerade nya lagerrelaterade API:er som förenklar, förbättrar prestandan för och lägger till funktioner i lager.
ID2D1DeviceContext och PushLayer
Gränssnittet ID2D1DeviceContext härleds från gränssnittet ID2D1RenderTarget och är nyckeln till att visa Direct2D-innehåll i Windows 8. Mer information om det här gränssnittet finns i Enheter och enhetskontexter. Med gränssnittet för enhetskontext kan du hoppa över att anropa metoden CreateLayer och sedan skicka NULL till metoden ID2D1DeviceContext::P ushLayer. Direct2D hanterar automatiskt lagerresursen och kan dela resurser mellan lager och effektdiagram.
D2D1_LAYER_PARAMETERS1 och D2D1_LAYER_OPTIONS1
Den D2D1_LAYER_PARAMETERS1-strukturen är likadan som D2D1_LAYER_PARAMETERS, förutom att den sista medlemmen i strukturen nu är en D2D1_LAYER_OPTIONS1 uppräkning.
D2D1_LAYER_OPTIONS1 har inget ClearType-alternativ och har två olika alternativ som du kan använda för att förbättra prestanda:
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND: Direct2D renderar primitiver till lagret utan att rensa det med transparent svart. Detta är inte standard, men i de flesta fall resulterar det i bättre prestanda.
D2D1_LAYER_OPTIONS1_IGNORE_ALPHA: om den underliggande ytan är inställd på D2D1_ALPHA_MODE_IGNOREkan Direct2D undvika att ändra alfakanalen i lagret. Använd inte detta i andra fall.
Blandningslägen
Från och med Windows 8 har enhetskontexten ett primitivt blandningsläge som avgör hur varje primitiv blandas med målytan. Det här läget gäller även för lager när du anropar metoden PushLayer.
Om du till exempel använder ett lager för att klippa ut primitiver med transparens anger du D2D1_PRIMITIVE_BLEND_COPY läge i enhetskontexten för korrekt resultat. I kopieringsläget linjärt interpolerar enhetens kontext alla fyra färgkanalerna, inklusive alfakanalen, för varje pixel med innehållet på målytan enligt lagrets geometriska mask.
Interoperabilitet
Från och med Windows 8 stöder Direct2D samverkan med Direct3D och GDI medan ett lager eller klipp pushas. Du anropar ID2D1GdiInteropRenderTarget::GetDC medan ett lager trycks för att interagera med GDI. Du anropar ID2D1DeviceContext::Flush och renderar sedan till den underliggande ytan för att samverka med Direct3D. Det är ditt ansvar att rendera inuti lagret eller klippet med Direct3D eller GDI. Om du försöker rendera utanför lagret eller klippa ut är resultatet odefinierat.
Skapa lager
Att arbeta med lager kräver kunskaper om CreateLayer, PushLayeroch PopLayer metoder och D2D1_LAYER_PARAMETERS struktur, som innehåller en uppsättning parametriska data som definierar hur lagret kan användas. I följande lista beskrivs metoderna och strukturen.
Anropa metoden CreateLayer för att skapa en lagerresurs.
Not
Från och med Windows 8 kan du hoppa över att anropa metoden CreateLayer och sedan skicka NULL till metoden PushLayer i ID2D1DeviceContext-gränssnittet. Detta är enklare och gör att Direct2D automatiskt kan hantera lagerresursen och dela resurser mellan lager och effektdiagram.
När återgivningsmålet har börjat ritas (efter att metoden BeginDraw har anropats) kan du använda metoden PushLayer. Metoden PushLayer lägger till det angivna lagret i återgivningsmålet, så att målet tar emot alla efterföljande ritningsåtgärder tills PopLayer- anropas. Den här metoden tar ett ID2D1Layer- objekt som returneras genom att anropa CreateLayer samt en layerParameters i D2D1_LAYER_PARAMETERS-strukturen. I följande tabell beskrivs strukturens fält.
Fält Beskrivning contentBounds Skiktets innehållsgräns. Innehållet kommer inte att visas utanför dessa gränser. Den här parametern är som standard InfiniteRect. När standardvärdet används anses innehållsgränsarna i praktiken vara gränserna för återgivningsmålet. geometriskmask (Valfritt) Området, som definieras av en ID2D1Geometry, som lagret ska klipps till. Ange till NULL om lagret inte ska klippas till en geometri. maskAntialiasMode Ett värde som anger antialiaseringsläget för den geometriska mask som anges av fältet geometricMask. maskTransform Ett värde som anger den transformering som tillämpas på den geometriska masken när lagret skapas. Detta är relativt till världstransformationen. ogenomskinlighet Opacitetsvärdet för lagret. Opaciteten för varje resurs i lagret multipliceras med det här värdet när de komponerar till målet. opacityBrush (Valfritt) En pensel som används för att ändra lagrets opacitet. Penseln mappas till lagret och alfakanalen för varje mappad penselpixel multipliceras med motsvarande skiktpixel. Ange till NULL- om lagret inte ska ha en ogenomskinlig mask. layerOptions Ett värde som anger om lagret har för avsikt att återge text med ClearType-antialias. Den här parametern är inaktiverad som standard. Om du aktiverar det kan ClearType fungera korrekt, men det resulterar i något långsammare återgivningshastighet. Not
Från och med Windows 8 kan du inte rendera med ClearType i ett lager, så parametern layerOptions bör alltid vara inställd på D2D1_LAYER_OPTIONS_NONE
För enkelhetens skull tillhandahåller Direct2D D2D1::LayerParameters metod som hjälper dig att skapa D2D1_LAYER_PARAMETERS strukturer.
Om du vill kompilera innehållet i lagret till återgivningsmålet anropar du metoden PopLayer. Du måste anropa metoden PopLayer innan du anropar metoden EndDraw.
I följande exempel visas hur du använder CreateLayer, PushLayeroch PopLayer. Alla fält i D2D1_LAYER_PARAMETERS-strukturen är inställda på deras standardvärden, förutom opacityBrush, som är inställd på en ID2D1RadialGradientBrush.
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(
D2D1::InfiniteRect(),
NULL,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::IdentityMatrix(),
1.0,
m_pRadialGradientBrush,
D2D1_LAYER_OPTIONS_NONE),
pLayer
);
pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));
pRT->FillRectangle(
D2D1::RectF(25.f, 25.f, 50.f, 50.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(50.f, 50.f, 75.f, 75.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(75.f, 75.f, 100.f, 100.f),
m_pSolidColorBrush
);
pRT->PopLayer();
}
SafeRelease(&pLayer);
Koden har utelämnats från det här exemplet.
Observera att när du anropar PushLayer och PopLayerkontrollerar du att varje PushLayer- har ett matchande PopLayer--anrop. Om det finns fler PopLayer- anrop än PushLayer--anrop placeras återgivningsmålet i ett feltillstånd. Om Flush anropas innan alla utestående lager poppas, placeras återgivningsmålet i ett feltillstånd och returnerar ett fel. Om du vill rensa feltillståndet använder du EndDraw.
Innehållsgräns
contentBounds anger gränsen för vad som ska dras till lagret. Endast de element inom innehållets gränser kombineras tillbaka i renderingsmålet.
Följande exempel visar hur du anger contentBounds så att den ursprungliga bilden klipps till innehållsgränsen med det övre vänstra hörnet på (10, 108) och det nedre högra hörnet på (121, 177). Följande bild visar den ursprungliga bilden och resultatet av att beskära bilden till innehållsgränserna.
HRESULT DemoApp::RenderWithLayerWithContentBounds(ID2D1RenderTarget *pRT)
{
HRESULT hr = S_OK;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 0));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(D2D1::RectF(10, 108, 121, 177)),
pLayer
);
pRT->DrawBitmap(m_pWaterBitmap, D2D1::RectF(0, 0, 128, 192));
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
Koden har utelämnats från det här exemplet.
Not
Den resulterande klippta bilden påverkas ytterligare om du anger en geometrisk mask. Mer information finns i avsnittet geometriska masker.
Geometriska masker
En geometrisk mask är antingen ett klipp eller en utstansning, definierat av ett ID2D1Geometry-objekt, som maskerar ett lager när det ritas av ett renderingsmål. Du kan använda geometricMask-fältet i strukturen D2D1_LAYER_PARAMETERS för att maskera resultatet till en geometri. Om du till exempel vill visa en bild maskerad med blockbokstaven "A" kan du först skapa en geometri som representerar blockbokstaven "A" och använda den geometrin som geometrimask för ett lager. När du sedan har överfört lagret kan du rita bilden. När lagret aktiveras blir bilden klippt till blockbokstaven "A" form.
Följande exempel visar hur du skapar en ID2D1PathGeometry- som innehåller en form av ett berg och skickar sedan sökvägsgeometrin till PushLayer. Den ritar sedan en bitmapp och kvadrater. Om det bara finns en bitmapp i lagret att återge använder du FillGeometry med en fastklämd bitmappsborste för effektivitet. Följande bild visar utdata från exemplet.
I det första exemplet definieras geometrin som ska användas som en mask.
hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry);
if(SUCCEEDED(hr))
{
ID2D1GeometrySink *pSink = NULL;
// Write to the path geometry using the geometry sink.
hr = m_pPathGeometry->Open(&pSink);
if (SUCCEEDED(hr))
{
pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
pSink->BeginFigure(
D2D1::Point2F(0, 90),
D2D1_FIGURE_BEGIN_FILLED
);
D2D1_POINT_2F points[7] = {
D2D1::Point2F(35, 30),
D2D1::Point2F(50, 50),
D2D1::Point2F(70, 45),
D2D1::Point2F(105, 90),
D2D1::Point2F(130, 90),
D2D1::Point2F(150, 60),
D2D1::Point2F(170, 90)
};
pSink->AddLines(points, 7);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
SafeRelease(&pSink);
}
I nästa exempel används geometrin som en mask för lagret.
HRESULT DemoApp::RenderWithLayerWithGeometricMask(ID2D1RenderTarget *pRT)
{
HRESULT hr;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 450));
pRT->PushLayer(
D2D1::LayerParameters(D2D1::InfiniteRect(), m_pPathGeometry),
pLayer
);
pRT->DrawBitmap(m_pLeafBitmap, D2D1::RectF(0, 0, 198, 132));
pRT->FillRectangle(
D2D1::RectF(50.f, 50.f, 75.f, 75.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(75.f, 75.f, 100.f, 100.f),
m_pSolidColorBrush
);
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
Koden har utelämnats från det här exemplet.
Notera
I allmänhet, om du anger en geometrisk mask, kan du använda standardvärdet InfiniteRectför contentBounds.
Om contentBounds är NULL och geometriskmask inte är NULL, är innehållsgränsen i själva verket gränserna för den geometriska masken efter att masktransformen har tillämpats.
Om contentBounds är icke-NULL och geometriskmask inte är NULL, klipps den transformerade geometriska masken effektivt mot innehållsgränsen och innehållsgränsen antas vara oändlig.
Ogenomskinliga masker
En ogenomskinlig mask är en mask, som beskrivs av en pensel eller bitmapp, som tillämpas på ett annat objekt för att göra objektet delvis eller helt transparent. Det gör att alfakanalen hos en pensel kan användas som en innehållsmask. Du kan till exempel definiera en radiell toningsborste som varierar från ogenomskinlig till transparent för att skapa en vinjetteffekt.
Exemplet som följer använder en ID2D1RadialGradientBrush (m_pRadialGradientBrush) som en ogenomskinlig mask. Den ritar sedan en bitmapp och kvadrater. Om det bara finns en bitmapp i lagret att återge använder du FillGeometry med en fastklämd bitmappsborste för effektivitet. Följande bild visar utdata från det här exemplet.
HRESULT DemoApp::RenderWithLayerWithOpacityMask(ID2D1RenderTarget *pRT)
{
HRESULT hr = S_OK;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(
D2D1::InfiniteRect(),
NULL,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::IdentityMatrix(),
1.0,
m_pRadialGradientBrush,
D2D1_LAYER_OPTIONS_NONE),
pLayer
);
pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));
pRT->FillRectangle(
D2D1::RectF(25.f, 25.f, 50.f, 50.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(50.f, 50.f, 75.f, 75.f),
m_pSolidColorBrush
);
pRT->FillRectangle(
D2D1::RectF(75.f, 75.f, 100.f, 100.f),
m_pSolidColorBrush
);
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
Koden har utelämnats från det här exemplet.
Anteckning
I det här exemplet används ett lager för att tillämpa en opacitetsmask på ett enda objekt för att hålla exemplet så enkelt som möjligt. När du använder en opacitetsmask på ett enda objekt är det effektivare att använda FillOpacityMask eller FillGeometry metoder i stället för ett lager.
Anvisningar om hur du använder en opacitetsmask utan att använda ett lager finns i översikten över ogenomskinlighetsmasker.
Alternativ till lager
Som tidigare nämnts kan ett stort antal lager påverka programmets prestanda negativt. För att förbättra prestandan, undvik att använda lager när det är möjligt; använd istället deras alternativ. I följande kodexempel visas hur du använder PushAxisAlignedClip och PopAxisAlignedClip för att klippa ut en region, som ett alternativ till att använda ett lager med innehållsgräns.
pRT->PushAxisAlignedClip(
D2D1::RectF(20, 20, 100, 100),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
pRT->FillRectangle(D2D1::RectF(0, 0, 200, 133), m_pOriginalBitmapBrush);
pRT->PopAxisAlignedClip();
Använd på samma sätt FillGeometry- med en fastklämd bitmappsborste som ett alternativ till att använda ett lager med en opacitetsmask när det bara finns ett innehåll i lagret att återge, som du ser i följande exempel.
m_pRenderTarget->FillGeometry(
m_pRectGeo,
m_pLinearFadeFlowersBitmapBrush,
m_pLinearGradientBrush
);
Som ett alternativ till att använda ett lager med en geometrisk mask bör du överväga att använda en bitmappsmask för att klippa ut en region, som du ser i följande exempel.
// D2D1_ANTIALIAS_MODE_ALIASED must be set for FillOpacityMask
// to function properly.
m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
m_pRenderTarget->FillOpacityMask(
m_pBitmapMask,
m_pOriginalBitmapBrush,
D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
&rcBrushRect,
NULL
);
m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
Slutligen, om du vill tillämpa opacitet på en enda form, bör du multiplicera opaciteten med penselfärgen och sedan rendera formen. Du behöver inte ett lager eller en bitmapp för opacitetsmask.
float opacity = 0.9f;
ID2D1SolidColorBrush *pBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f * opacity)),
&pBrush
);
m_pRenderTarget->FillRectangle(
D2D1::RectF(50.0f, 50.0f, 75.0f, 75.0f),
pBrush
);
Klippa en godtycklig form
Bilden här visar resultatet av att tillämpa ett klipp på en bild.
Du kan få det här resultatet genom att använda lager med en geometrimask eller metoden FillGeometry med en ogenomskinlig pensel.
Här är ett exempel som använder ett lager:
// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
D2D1::LayerParameters(
boundsRect,
geometricMask));
Här är ett exempel som använder metoden FillGeometry:
// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
D2D1::BitmapProperties(
D2D1_BITMAP_OPTIONS_TARGET,
D2D1::PixelFormat(
DXGI_FORMAT_A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX, dpiY),
&opacityBitmap);
m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();
// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
D2D1::BitmapBrushProperties(),
D2D1::BrushProperties(),
&bitmapBrush);
// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry(
clipGeometry.Get(),
brush.Get(),
opacityBrush.Get());
När du anropar PushLayer-metoden i det här kodexemplet skickar du inte in ett lager som skapats av appen. Direct2D skapar ett lager åt dig. Direct2D kan hantera allokeringen och förstörelsen av den här resursen utan någon inblandning från appen. Detta gör att Direct2D kan återanvända lager internt och tillämpa resurshanteringsoptimeringar.
Note
I Windows 8 har många optimeringar gjorts för användning av lager och vi rekommenderar att du försöker använda lager-API:er i stället för FillGeometry när det är möjligt.
Axelriktade klipp
Om den region som ska klippas ut är i linje med axeln på ritytan, istället för slumpmässigt. Det här fallet passar för att använda en klipprektangel i stället för ett lager. Prestandavinsten är mer för aliasgeometri än antialiaserad geometri. Mer information om axeljusterade klipp finns i avsnittet PushAxisAlignedClip.
Relaterade ämnen