Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Direct2D sangat cocok untuk aplikasi grafis yang memerlukan penyajian sisi server di Windows Server. Gambaran umum ini menjelaskan dasar-dasar penggunaan Direct2D untuk penyajian sisi server. Ini berisi bagian berikut:
- Persyaratan untuk Server-Side Pemrosesan
- Opsi untuk API yang Tersedia
- GDI
- GDI+
- Direct2D
- Cara Menggunakan Direct2D untuk Server-Side Rendering
- Kesimpulan
- Topik terkait
Persyaratan untuk Server-Side Rendering
Berikut ini adalah skenario umum untuk server bagan: bagan dan grafik dirender di server dan dikirimkan sebagai bitmap sebagai respons terhadap permintaan Web. Server mungkin dilengkapi dengan kartu grafis kelas bawah atau tanpa kartu grafis sama sekali.
Skenario ini mengungkapkan tiga persyaratan aplikasi. Pertama, aplikasi harus menangani beberapa permintaan bersamaan secara efisien, terutama pada server multicore. Kedua, aplikasi harus menggunakan penyajian perangkat lunak saat berjalan di server dengan kartu grafis low-end atau tanpa kartu grafis. Terakhir, aplikasi harus berjalan sebagai layanan di Sesi 0 sehingga tidak mengharuskan pengguna untuk masuk. Untuk informasi selengkapnya tentang Sesi 0, lihat Kompatibilitas Aplikasi - Isolasi Sesi 0 dan Panduan Nol Sesi untuk Driver UMDF.
Opsi untuk API yang Tersedia
Ada tiga opsi untuk penyajian sisi server: GDI, GDI+ dan Direct2D. Seperti GDI dan GDI+, Direct2D adalah API penyajian 2D asli yang memberi aplikasi kontrol lebih besar atas penggunaan perangkat grafis. Selain itu, Direct2D secara unik mendukung fasilitas berulir tunggal dan berulir banyak. Bagian berikut membandingkan setiap API dalam hal kualitas gambar dan penyajian sisi server multithreaded.
GDI
Tidak seperti Direct2D dan GDI+, GDI tidak mendukung fitur gambar berkualitas tinggi. Misalnya, GDI tidak mendukung antialias untuk membuat garis halus dan hanya memiliki dukungan terbatas untuk transparansi. Berdasarkan hasil pengujian performa grafis pada Windows 7 dan Windows Server 2008 R2, Direct2D menskalakan lebih efisien daripada GDI, meskipun desain ulang kunci di GDI. Untuk informasi selengkapnya tentang hasil pengujian ini, lihat Rekayasa Windows 7 Graphics Performance.
Selain itu, aplikasi yang menggunakan GDI dibatasi hingga 10240 handle GDI per proses dan 65536 handle GDI per sesi. Alasannya adalah secara internal Windows menggunakan 16-bit WORD untuk menyimpan indeks handle untuk setiap sesi.
GDI+
Sementara GDI+ mendukung antilias dan alpha blending untuk gambar berkualitas tinggi, masalah utama GDI+ dalam skenario server adalah tidak mendukung pengoperasian pada Sesi 0. Karena Sesi 0 hanya mendukung fungsionalitas non-interaktif, fungsi yang secara langsung atau tidak langsung berinteraksi dengan perangkat tampilan karena itu akan menerima kesalahan. Contoh fungsi tertentu tidak hanya mencakup yang berurusan dengan perangkat tampilan, tetapi juga yang secara tidak langsung berurusan dengan driver perangkat.
Mirip dengan GDI, GDI+ dibatasi oleh mekanisme pengunciannya. Mekanisme penguncian di GDI+ sama di Windows 7 dan Windows Server 2008 R2 seperti pada versi sebelumnya.
Direct2D
Direct2D adalah API grafis 2-D dipercepat perangkat keras dan mode langsung yang memberikan performa tinggi dan penyajian berkualitas tinggi. Ini menawarkan pabrik berulir tunggal dan multithreaded dan penskalaan linier penyajian perangkat lunak kasar.
Untuk melakukan ini, Direct2D mendefinisikan antarmuka faktori utama. Sebagai aturan, objek yang dibuat di pabrik hanya dapat digunakan dengan objek lain yang dibuat dari pabrik yang sama. Pemanggil dapat meminta pabrik berutas tunggal atau berutas banyak pada saat pembuatannya. Jika pabrik berutas tunggal diminta, maka tidak ada penguncian utas yang dilakukan. Jika pemanggil meminta pabrik multithreaded, maka kunci utas seluruh pabrik diperoleh setiap kali ada panggilan yang dilakukan ke Direct2D.
Selain itu, penguncian utas di Direct2D lebih terperinci daripada di GDI dan GDI+, sehingga peningkatan jumlah utas berdampak minimal pada performa.
Cara Menggunakan Direct2D untuk Server-Side Rendering
Bagian berikut menjelaskan cara menggunakan penyajian perangkat lunak, cara menggunakan pabrik berulir tunggal dan multithreaded secara optimal, dan cara menggambar dan menyimpan gambar kompleks ke file.
Penyajian Perangkat Lunak
Aplikasi sisi server menggunakan penyajian perangkat lunak dengan membuat target render IWICBitmap, dengan jenis target render diatur ke D2D1_RENDER_TARGET_TYPE_SOFTWARE atau D2D1_RENDER_TARGET_TYPE_DEFAULT. Untuk informasi lebih lanjut tentang render target IWICBitmap, lihat metode ID2D1Factory::CreateWicBitmapRenderTarget; untuk informasi lebih lanjut tentang tipe render target, lihat D2D1_RENDER_TARGET_TYPE.
Multithreading
Mengetahui cara membuat dan berbagi objek produksi serta target render di antara beberapa utas dapat memiliki dampak yang signifikan terhadap kinerja aplikasi. Tiga angka berikut menunjukkan tiga pendekatan yang bervariasi. Pendekatan optimal ditunjukkan pada gambar 3.
Pada gambar 1, utas yang berbeda berbagi pabrik yang sama dan target render yang sama. Pendekatan ini dapat menyebabkan hasil yang tidak dapat diprediksi dalam kasus ketika beberapa utas secara bersamaan mengubah status target render bersama, seperti secara bersamaan mengatur matriks transformasi. Karena penguncian internal di Direct2D tidak menyinkronkan sumber daya bersama seperti target render, pendekatan ini dapat menyebabkan panggilan BeginDraw gagal di utas 1, karena di utas 2, panggilan BeginDraw sudah menggunakan target render bersama.
Untuk menghindari hasil yang tidak dapat diprediksi yang ditemui pada gambar 1, gambar 2 menunjukkan pabrik multithreaded dengan setiap utas memiliki target render sendiri. Pendekatan ini berhasil, tetapi pada dasarnya berfungsi sebagai aplikasi utas tunggal. Alasannya adalah bahwa penguncian seluruh pabrik hanya berlaku untuk tingkat operasi gambar dan semua panggilan gambar di pabrik yang sama akan diserialisasi. Akibatnya, utas 1 menjadi diblokir saat mencoba memasukkan panggilan gambar, sementara utas 2 berada di tengah-tengah menjalankan panggilan gambar lain.
Gambar 3 menunjukkan pendekatan optimal, di mana pabrik satu utas dan target render satu utas digunakan. Karena tidak ada penguncian yang dilakukan saat menggunakan pabrik berulir tunggal, operasi menggambar di setiap utas dapat berjalan bersamaan untuk mencapai performa optimal.
Membuat Sebuah File Bitmap
Untuk menghasilkan file bitmap menggunakan penyajian perangkat lunak, gunakan target render IWICBitmap. Gunakan IWICStream untuk menulis bitmap ke file. Gunakan IWICBitmapFrameEncode untuk mengodekan bitmap ke dalam format gambar tertentu. Contoh kode berikut menunjukkan cara menggambar dan menyimpan gambar berikut ke file.
Contoh kode ini pertama-tama membuat IWICBitmap dan target render IWICBitmap. Kemudian merender gambar dengan beberapa teks, geometri jalur yang mewakili kaca jam, dan kaca jam yang diubah menjadi bitmap WIC. Kemudian menggunakan IWICStream::InitializeFromFilename untuk menyimpan bitmap ke file. Jika aplikasi Anda perlu menyimpan bitmap dalam memori, gunakan IWICStream::InitializeFromMemory sebagai gantinya. Terakhir, ia menggunakan IWICBitmapFrameEncode untuk mengodekan bitmap.
// Create an IWICBitmap and RT
static const UINT sc_bitmapWidth = 640;
static const UINT sc_bitmapHeight = 480;
if (SUCCEEDED(hr))
{
hr = pWICFactory->CreateBitmap(
sc_bitmapWidth,
sc_bitmapHeight,
GUID_WICPixelFormat32bppBGR,
WICBitmapCacheOnLoad,
&pWICBitmap
);
}
// Set the render target type to D2D1_RENDER_TARGET_TYPE_DEFAULT to use software rendering.
if (SUCCEEDED(hr))
{
hr = pD2DFactory->CreateWicBitmapRenderTarget(
pWICBitmap,
D2D1::RenderTargetProperties(),
&pRT
);
}
// Create text format and a path geometry representing an hour glass.
if (SUCCEEDED(hr))
{
static const WCHAR sc_fontName[] = L"Calibri";
static const FLOAT sc_fontSize = 50;
hr = pDWriteFactory->CreateTextFormat(
sc_fontName,
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
sc_fontSize,
L"", //locale
&pTextFormat
);
}
if (SUCCEEDED(hr))
{
pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
hr = pD2DFactory->CreatePathGeometry(&pPathGeometry);
}
if (SUCCEEDED(hr))
{
hr = pPathGeometry->Open(&pSink);
}
if (SUCCEEDED(hr))
{
pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
pSink->BeginFigure(
D2D1::Point2F(0, 0),
D2D1_FIGURE_BEGIN_FILLED
);
pSink->AddLine(D2D1::Point2F(200, 0));
pSink->AddBezier(
D2D1::BezierSegment(
D2D1::Point2F(150, 50),
D2D1::Point2F(150, 150),
D2D1::Point2F(200, 200))
);
pSink->AddLine(D2D1::Point2F(0, 200));
pSink->AddBezier(
D2D1::BezierSegment(
D2D1::Point2F(50, 150),
D2D1::Point2F(50, 50),
D2D1::Point2F(0, 0))
);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
if (SUCCEEDED(hr))
{
static const D2D1_GRADIENT_STOP stops[] =
{
{ 0.f, { 0.f, 1.f, 1.f, 1.f } },
{ 1.f, { 0.f, 0.f, 1.f, 1.f } },
};
hr = pRT->CreateGradientStopCollection(
stops,
ARRAYSIZE(stops),
&pGradientStops
);
}
if (SUCCEEDED(hr))
{
hr = pRT->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(
D2D1::Point2F(100, 0),
D2D1::Point2F(100, 200)),
D2D1::BrushProperties(),
pGradientStops,
&pLGBrush
);
}
if (SUCCEEDED(hr))
{
hr = pRT->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
);
}
if (SUCCEEDED(hr))
{
// Render into the bitmap.
pRT->BeginDraw();
pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
D2D1_SIZE_F rtSize = pRT->GetSize();
// Set the world transform to a 45 degree rotation at the center of the render target
// and write "Hello, World".
pRT->SetTransform(
D2D1::Matrix3x2F::Rotation(
45,
D2D1::Point2F(
rtSize.width / 2,
rtSize.height / 2))
);
static const WCHAR sc_helloWorld[] = L"Hello, World!";
pRT->DrawText(
sc_helloWorld,
ARRAYSIZE(sc_helloWorld) - 1,
pTextFormat,
D2D1::RectF(0, 0, rtSize.width, rtSize.height),
pBlackBrush);
// Reset back to the identity transform.
pRT->SetTransform(D2D1::Matrix3x2F::Translation(0, rtSize.height - 200));
pRT->FillGeometry(pPathGeometry, pLGBrush);
pRT->SetTransform(D2D1::Matrix3x2F::Translation(rtSize.width - 200, 0));
pRT->FillGeometry(pPathGeometry, pLGBrush);
hr = pRT->EndDraw();
}
if (SUCCEEDED(hr))
{
// Save the image to a file.
hr = pWICFactory->CreateStream(&pStream);
}
WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
// Use InitializeFromFilename to write to a file. If there is need to write inside the memory, use InitializeFromMemory.
if (SUCCEEDED(hr))
{
static const WCHAR filename[] = L"output.png";
hr = pStream->InitializeFromFilename(filename, GENERIC_WRITE);
}
if (SUCCEEDED(hr))
{
hr = pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder);
}
if (SUCCEEDED(hr))
{
hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
}
if (SUCCEEDED(hr))
{
hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL);
}
// Use IWICBitmapFrameEncode to encode the bitmap into the picture format you want.
if (SUCCEEDED(hr))
{
hr = pFrameEncode->Initialize(NULL);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->SetSize(sc_bitmapWidth, sc_bitmapHeight);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->SetPixelFormat(&format);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->WriteSource(pWICBitmap, NULL);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->Commit();
}
if (SUCCEEDED(hr))
{
hr = pEncoder->Commit();
}
Kesimpulan
Seperti yang terlihat dari hal di atas, menggunakan Direct2D untuk penyajian sisi server sederhana dan mudah. Selain itu, ini memberikan rendering berkualitas tinggi dan sangat paralel yang dapat berjalan di lingkungan server berprivileg rendah.
Topik terkait