Symbian3/PDK/Source/GUID-8DF46A11-874A-52E5-9298-C083EA633BA0.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Tue, 30 Mar 2010 11:56:28 +0100
changeset 5 f345bda72bc4
parent 3 46218c8b8afa
child 14 578be2adaf3e
permissions -rw-r--r--
Week 12 contribution of PDK documentation_content. See release notes for details. Fixes Bug 2054, Bug 1583, Bug 381, Bug 390, Bug 463, Bug 1897, Bug 344, Bug 1319, Bug 394, Bug 1520, Bug 1522, Bug 1892"

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-8DF46A11-874A-52E5-9298-C083EA633BA0" xml:lang="en"><title>Implementing
Dynamic DSA Allocation</title><shortdesc>This topic describes how device creators can allocate the Direct
Screen Access (DSA) buffer dynamically. This feature is new in Symbian^3 (S^3). </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p> <b>Target audience</b>: Device creators. </p>
<section><title>Overview</title> <p>Before the introduction of ScreenPlay,
applications (such as video and EGL games) that required high frame rates
used Direct Screen Access (DSA) to bypass the Window Server and draw directly
to the frame buffer (video memory). However, some interaction with the Window
Server was necessary in order to prevent the application from drawing over
other applications' data. The frame buffer was allocated at device startup
and was never freed. </p> <p>In ScreenPlay, applications that require a high
frame rate can render directly to <xref href="GUID-ADA8CECB-0E70-5B9C-8F36-0714AAF0CD13.dita">composition
surfaces</xref>. In ScreenPlay the Window Server's content is also rendered
to a composition surface, which is known as the <b>UI surface</b>. This means
that the Window Server and its render stages do not render directly to the
frame buffer. However, DSA is still supported in order to provide backwards
compatibility. </p> <p>The DSA buffer is now just another buffer (known as
the <b>DSA buffer</b>), which the Window Server process makes use of only
when a client uses DSA on a visible window. This means that it is no longer
necessary to allocate the DSA buffer at startup and not free it. In fact to
do so in ScreenPlay is wasteful of resources. </p> <p>For this reason, it
is now possible to allocate the DSA buffer as a <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita">shared
chunk</xref> and free it when it is not in use. This requires changes in the
implementation of the LCD Driver (also known as the <xref href="GUID-8C22AF20-EE0E-5AD2-BEFD-FED5A7DBB09B.dita">LCD
Extension</xref>). For example, in order to free the DSA buffer when it is
no longer in use, the LCD Driver must keep track of the processes that use
the buffer and when they finish with it. These changes can be implemented
regardless whether ScreenPlay is in use. </p> <p> <i>Note</i>: Semi-transparent
UI content over content provided by Direct Screen Access (DSA) has never been
supported and ScreenPlay does not change this. </p> </section>
<section><title>DSA client-side API changes</title> <p>To use DSA, the client
creates an instance of <xref href="GUID-24C7AE25-B44A-3B6F-AA05-EA90A8D36129.dita"><apiname>CDirectScreenAccess</apiname></xref>. This allows
the client to draw directly to the DSA buffer and to determine the visible
area of its window and be notified when the visible area changes. DSA is typically
performed by using the <xref href="GUID-B229156F-2344-3F46-8542-AC65882D80DE.dita"><apiname>CFbsScreenDevice</apiname></xref> returned by <xref href="GUID-24C7AE25-B44A-3B6F-AA05-EA90A8D36129.dita#GUID-24C7AE25-B44A-3B6F-AA05-EA90A8D36129/GUID-9528CBFF-7D01-3B62-81B1-7F9B2C799C14"><apiname>CDirectScreenAccess::ScreenDevice()</apiname></xref>. </p> <p>However,
applications can call the HAL user-side API (described below) to allocate
the DSA buffer (if not already allocated) and obtain the DSA buffer's address
directly. Clients that do this can now use DSA simply in order to be notified
when the visible area changes and not for accessing the DSA buffer itself.
This is called <b>region-tracking DSA</b>. (<xref href="GUID-B229156F-2344-3F46-8542-AC65882D80DE.dita"><apiname>CFbsScreenDevice</apiname></xref> also
obtains the DSA address through the use of the HAL user-side API.) </p> <p>To
use region-tracking DSA, call the following overload of the <codeph>CDirectScreenAccess::NewL()</codeph> function
and pass <codeph>ETrue</codeph> as the final argument: </p> <p> <xref href="GUID-24C7AE25-B44A-3B6F-AA05-EA90A8D36129.dita#GUID-24C7AE25-B44A-3B6F-AA05-EA90A8D36129/GUID-6C26D5CD-0B55-3D30-B365-9C431BDD3721"><apiname>CDirectScreenAccess::NewL(RWsSession&amp;,CWsScreenDevice&amp;,RWindowBase&amp;,MDirectScreenAccess&amp;,TBool)</apiname></xref> </p> <p>This does not allocate a screen device and graphics context. It
therefore does not cause the DSA buffer to be allocated. </p> <p>Here is an
example that shows how to create a <xref href="GUID-24C7AE25-B44A-3B6F-AA05-EA90A8D36129.dita"><apiname>CDirectScreenAccess</apiname></xref> object
to track visible regions only: </p> <codeblock id="GUID-E378E1D5-C700-5AC6-AE3B-6CF9DA993671" xml:space="preserve">CDirectScreenAccess * cDsa = NULL;
    
// Specify additional parameter to NewL to indicate region tracking only.
cDsa = CDirectScreenAccess::NewL(TheClient-&gt;iWs,*TheClient-&gt;iScreen,*win,
           *this, ETrue); 
   
// In this mode, the client cannot get a screen device or graphics 
// context from the DSA object.
CFbsScreenDevice sd = cDsa-&gt;ScreenDevice();
CFbsBitGc gc = cDsa-&gt;Gc();
    
ASSERT(sd == NULL)
ASSERT(gc == NULL)
</codeblock> </section>
<section> <title>User-side HAL API changes</title> <p>The user-side HAL API
is a set of static functions that get and set the hardware attributes of the
device. For general information about the interface to HAL, see <xref href="GUID-9AE254D4-AA60-579E-8D9D-F2797106A413.dita">User-Side
Hardware Abstraction Technology</xref>. </p> <p>The <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-573C49D6-7763-37AE-B2B2-4C8FB1327E21"><apiname>HAL::Get()</apiname></xref> function
is used to obtain information about the DSA buffer memory. </p> <codeblock id="GUID-A50C3B6C-364C-58B8-B5FC-6472C5C8FF09" xml:space="preserve">static IMPORT_C TInt Get(TAttribute aAttribute, TInt &amp;aValue); 
static IMPORT_C TInt Get(TInt aDeviceNumber, TAttribute aAttribute, 
     TInt &amp;aValue);</codeblock> <p>In versions earlier than S^3, in order
to obtain the memory address of the DSA buffer, a client calls <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-573C49D6-7763-37AE-B2B2-4C8FB1327E21"><apiname>HAL::Get()</apiname></xref> with
an attribute of <xref href="GUID-8BE90160-2C60-3582-82C8-4A108C7C0317.dita#GUID-8BE90160-2C60-3582-82C8-4A108C7C0317/GUID-4702237B-185B-33B1-B0B6-DE388DBDE294"><apiname>HALData::EDisplayMemoryAddress</apiname></xref>. If successful,
the call returns <codeph>KErrNone</codeph> and sets the <codeph>aValue</codeph> parameter
to the virtual address of the DSA buffer in the caller’s process. If the DSA
buffer cannot be allocated, the call returns <codeph>KErrNoMemory</codeph> and
sets the <codeph>aValue</codeph> parameter to NULL. </p> <p>From S^3 onwards,
a client can obtain a handle to the DSA buffer by calling <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-573C49D6-7763-37AE-B2B2-4C8FB1327E21"><apiname>HAL::Get()</apiname></xref> with
an attribute of <xref href="GUID-8BE90160-2C60-3582-82C8-4A108C7C0317.dita#GUID-8BE90160-2C60-3582-82C8-4A108C7C0317/GUID-6124E485-D8A6-3399-AA6C-7021D130591D"><apiname>HALData::EDisplayMemoryHandle</apiname></xref>. If successful,
the call returns <codeph>KErrNone</codeph> and sets the <codeph>aValue</codeph> parameter
to the value of an <xref href="GUID-326A2F4D-0E99-31C0-A35D-E8BF45913F07.dita"><apiname>RChunk</apiname></xref> handle in the caller’s process.
If the DSA buffer cannot be allocated, the call returns <codeph>KErrNoMemory</codeph> and
sets the <codeph>aValue</codeph> parameter to 0. </p> <p>The advantage of
using a handle is twofold: </p> <ul>
<li id="GUID-187317E0-0EED-5C8F-AB31-542D6EA0CBF2"><p>The memory chunk exists
for as long as the handle is open. </p> </li>
<li id="GUID-7984A11D-F7A2-5C1A-AB11-628911BCA292"><p>The handle is automatically
closed by the kernel if the process holding it exits prematurely. </p> </li>
</ul> <p>When possible, legacy clients should be changed to take advantage
of the new <xref href="GUID-8BE90160-2C60-3582-82C8-4A108C7C0317.dita#GUID-8BE90160-2C60-3582-82C8-4A108C7C0317/GUID-6124E485-D8A6-3399-AA6C-7021D130591D"><apiname>HALData::EDisplayMemoryHandle</apiname></xref> attribute. This
means that you need to modify <codeph>HAL::Get(EDisplayMemoryAddress)</codeph> calls
to use <xref href="GUID-8BE90160-2C60-3582-82C8-4A108C7C0317.dita#GUID-8BE90160-2C60-3582-82C8-4A108C7C0317/GUID-6124E485-D8A6-3399-AA6C-7021D130591D"><apiname>HALData::EDisplayMemoryHandle</apiname></xref> to obtain a handle
to the DSA's shared chunk. You also need to add code to close this handle
when the memory is no longer required. </p> <p>For example, replace the following
code: </p> <codeblock id="GUID-DAB0136B-A5A9-5B15-9C88-1A37B04804AB" xml:space="preserve">err = HAL::Get(screenId, HALData::EDisplayMemoryAddress, dsaAddr);</codeblock> <p>With something like this: </p> <codeblock id="GUID-BD8049BB-378C-5C56-A19B-96227C71A325" xml:space="preserve">err = HAL::Get(screenId, HALData::EDisplayMemoryHandle, val);
if (err == KErrNone)
    {
    RChunk chunk;
    err = chunk.SetReturnedHandle(val);
    if (err == KErrNone)
        {
        iDSAChunk = chunk;
        err = iDSAChunk.Duplicate(RThread(), EOwnerProcess);
        chunk.Close();
        if (err == KErrNone)
            {
            dsaAddr = (TInt) iDSAChunk.Base();
            }
else if (err == KErrNotSupported)
    {
    err = HAL::Get(screenId, HALData::EDisplayMemoryAddress, dsaAddr);
    }
</codeblock> </section>
<section><title>Kernel-side HAL changes</title> <p>HAL requests are handled
on the kernel side by HAL handlers. A single HAL handler deals with all the
HAL attributes defined in a particular HAL group. Each HAL group has a one-to-one
relationship with a HAL handler. <codeph>EHalGroupDisplay</codeph> identifies
the group associated with the HAL display attributes. </p> <p>In S^3 the <xref href="GUID-BB011D9B-105F-345C-9FC0-39B0BA509394.dita"><apiname>TDisplayHalFunction</apiname></xref> enum
has two new attributes—<codeph>EDisplayHalGetDisplayMemoryAddress</codeph> and <codeph>EDisplayHalGetDisplayMemoryHandle</codeph>.
These allow the generic user-side HAL code to obtain the DSA buffer's address
and handle independently of all of the other display attributes. </p> </section>
<section><title>Handling HAL::Get(EDisplayMemoryAddress)</title> <p>In versions
earlier than S^3, the DSA buffer address is returned from the HAL handler
as part of a <xref href="GUID-C4712A78-6C58-39ED-AF84-11038DB8571D.dita"><apiname>TVideoInfoV01</apiname></xref> class in response to an <codeph>EDisplayHalCurrentModeInfo</codeph> request.
The user-side HAL code then extracts the address from the <xref href="GUID-C4712A78-6C58-39ED-AF84-11038DB8571D.dita"><apiname>TVideoInfoV01</apiname></xref> structure
and returns it. </p> <p><b>Configuration file setting </b> </p> <p>The HAL
configuration file <filepath>config.hcf</filepath> therefore includes the
following: </p> <codeblock id="GUID-F496B803-B7B8-57D4-B083-9219D4F849DB" xml:space="preserve">EDisplayMemoryAddress=ProcessDisplayCurrentModeInfo</codeblock> <p><b>Modifications
to generic HAL code </b> </p> <p>In S^3 the switch case for <codeph>EDisplayMemoryAddress</codeph> in <codeph>ProcessDisplayCurrentModeInfo()</codeph> is as follows: </p> <codeblock id="GUID-7E2FC07B-670D-57BA-BF3E-A4432BF83E81" xml:space="preserve">case HAL::EDisplayMemoryAddress:
    
// If the address is zero, the actual address
// is returned by EDisplayHalGetDisplayMemoryAddress
if (info.iVideoAddress == 0)  
    {
    r = UserSvr::HalFunction(EHalGroupDisplay, 
                             EDisplayHalGetDisplayMemoryAddress, 
                             aInOut, (TAny*)EFalse, aDeviceNumber);
    }
else
    {
    *(TInt*)aInOut = info.iVideoAddress;
    }
break;
</codeblock> <p><b>Dealing with HAL::GetAll() </b> </p> <p> <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-EF03B832-E9AA-32CF-903F-DFFA63A3E9AB"><apiname>HAL::GetAll()</apiname></xref> sets
the input parameters passed to the HAL handler to -1. You can use this in
the LCD Driver to determine whether the call for the DSA buffer's address
is from <codeph>HAL::GetAll()</codeph> and if it is, to not allocate the memory.
For example: </p> <codeblock id="GUID-8734B0EF-A2A2-5929-972F-56F7E0195940" xml:space="preserve">case EDisplayHalGetDisplayMemoryAddress:
    {
    TInt val = 0;
    TInt passedIn = 0;
    kumemget32(&amp;passedIn, a1, sizeof(TInt));
    
    // Not from a GetAll().
    if (passedIn != -1)    
        {
        r = DisplayMemoryAddress(aDeviceNumber, val);
        }
    else
        {
        r = KErrNone;
        }
    
    // Write the value returned back to the user side.
    kumemput32(a1, &amp;val, sizeof(TInt));
    }
    break;
</codeblock> <p><b>Keeping track of processes that call HAL::Get(EDisplayMemoryAddress) </b> </p> <p>Legacy
DSA clients request the DSA buffer address rather than the handle and assume
that the address will remain valid for the lifetime of the process. The LCD
Driver needs to keep track of processes that call <codeph>HAL::Get(EDisplayMemoryAddress)</codeph> and
free the DSA buffer when the last of these processes has exited. </p> <p>The
LCD Driver must therefore maintain a list of the relevant processes and the
address of the DSA buffer for each one. When the number of processes using
a buffer address returns to zero, the buffer is freed. </p> <p>To track the
usage, the LCD Driver creates a new shared chunk for each process that calls <codeph>HAL::Get(EDisplayMemoryAddress)</codeph>.
The LCD Driver then calls <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-BA56B205-60D8-326E-8340-3F78CCEA3DD1"><apiname>Kern::MakeHandleAndOpen()</apiname></xref> to
create a user handle to the shared chunk for the calling process. The LCD
Driver closes the kernel-side handle to the chunk. </p> <p>There is then a
handle to the shared chunk in the user process, which means that the shared
chunk stays open for as long as the process exists. When the user process
exits, the kernel closes any open handles that the process owns. This causes
the deletion of the shared chunk and its Deferred Function Call (DFC) to run.
The DFC removes the process from the list and decrements the reference count
of users of the DSA memory. </p> <p>Here is the sequence when a process calls <codeph>HAL::Get(EDisplayMemoryAddress)</codeph> for
the first time: </p> <ol id="GUID-DA7B9F91-6F52-532C-8E67-8DE89B1EFD42">
<li id="GUID-2055954D-2B13-5307-93A6-78936172416C"><p>Legacy process <i>X</i> implicitly
calls <codeph>HAL::Get(EDisplayMemoryAddress)</codeph> for the first time
by creating a DSA session that creates a <xref href="GUID-B229156F-2344-3F46-8542-AC65882D80DE.dita"><apiname>CFbsScreenDevice</apiname></xref>. </p> </li>
<li id="GUID-33A00E2F-B04C-51CE-9993-661DFF5BE00B"><p>The driver looks for
process <i>X</i> in the list of processes and addresses and does not find
it. </p> </li>
<li id="GUID-A8E33530-C089-5C85-9563-A39BBA9259F2"><p>The driver creates a
shared chunk for process <i>X</i> with a destruction DFC. </p> </li>
<li id="GUID-19CDF330-315D-5806-AB3D-9AB8857A02A4"><p>The driver creates a
user-side handle to the shared chunk. </p> </li>
<li id="GUID-E13883F3-6418-5920-A16A-8327744E6AF1"><p>The driver closes its <xref href="GUID-85454082-6734-3F1D-983F-734D4C2AB12D.dita"><apiname>DChunk</apiname></xref> handle
to the shared chunk. </p> </li>
<li id="GUID-8CF22900-AD3C-528D-B88A-74AC59BAAA20"><p>The driver calls <xref href="GUID-AC098719-7AD6-3B48-9BE3-7DCEADA3530B.dita#GUID-AC098719-7AD6-3B48-9BE3-7DCEADA3530B/GUID-0632CC60-AF0C-36F5-8E8F-3D8AD2568E31"><apiname>TUint8*
Kern::ChunkUserBase(DChunk*                 aChunk, DThread* aThread)</apiname></xref> to
get the address of the shared chunk in the user process . </p> </li>
<li id="GUID-0180A075-BF6B-53E4-8B6F-38BE083C58DA"><p>The driver stores the
calling process's ID and the address of the shared chunk in a table. </p> </li>
<li id="GUID-3663A069-09FA-55DF-9EA7-F1875B379569"><p>The driver returns the
address of the shared chunk to the calling process. </p> </li>
</ol> <p>Here is the sequence when the same process calls <codeph>HAL::Get(EDisplayMemoryAddress)</codeph> again: </p> <ol id="GUID-E7D5E120-364C-5CA6-BE4E-56563F58A293">
<li id="GUID-57947C06-0BA1-5CB0-AB3F-493D71510A95"><p>Legacy process <i>X</i> implicitly
calls <codeph>HAL::Get(EDisplayMemoryAddress)</codeph> again by creating a
DSA session that creates a <xref href="GUID-B229156F-2344-3F46-8542-AC65882D80DE.dita"><apiname>CFbsScreenDevice</apiname></xref>. </p> </li>
<li id="GUID-493E5ABC-5032-5653-A87B-27441F0AF88E"><p>The driver looks for
the process in the list of processes and addresses. </p> </li>
<li id="GUID-6CF1A43C-966E-59EF-BA68-BB1D5CA5A4F0"><p>The driver returns the
address previously given to the process. </p> </li>
</ol> <p>Here is the sequence when the same process exits: </p> <ol id="GUID-388DC71E-FD9B-5A56-8B3D-520159FA8939">
<li id="GUID-B95DB340-C730-5419-ADB8-0B5B10F46556"><p>The kernel cleans up
any open handles for the exiting process. </p> </li>
<li id="GUID-E8654886-77E4-5748-A0BE-A0E3CCCC752A"><p>The shared chunk destruction
DFC executes and removes the process from the list and decrements the DSA
usage count. </p> </li>
<li id="GUID-68624448-1DCF-591E-97EF-F0B46F656FC8"><p>The DFC checks the DSA
usage count and if it is zero, the DFC frees the DSA memory. </p> </li>
</ol> </section>
<section><title>Handling HAL::Get(EDisplayMemoryHandle)</title> <p>In S^3
there is a new <codeph>GetDisplayMemoryHandle()</codeph> function in the user-side
HAL implementation. This function is the handler for the new <codeph>EDisplayMemoryHandle</codeph> attribute. </p> <p><b>Configuration
file setting </b> </p> <p>The following line therefore needs to be added to
the <filepath>config.hcf</filepath> file: </p> <codeblock id="GUID-90AEC511-D592-5755-A569-7703A09EE40C" xml:space="preserve">EDisplayMemoryHandle=GetDisplayMemoryHandle</codeblock> <p><b>Dealing with HAL::GetAll() </b> </p> <p> <xref href="GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8.dita#GUID-BD00E7FC-C234-3111-87A5-10F79EB0F2B8/GUID-EF03B832-E9AA-32CF-903F-DFFA63A3E9AB"><apiname>HAL::GetAll()</apiname></xref> sets
the input parameters passed to the HAL handler to -1. You can use this in
the LCD Driver to determine whether the call for the DSA buffer's address
handle is from <codeph>HAL::GetAll()</codeph> and to take appropriate action.
For example: </p> <codeblock id="GUID-22A22111-1B29-59F4-B3F7-83E43077E0FD" xml:space="preserve">case EDisplayHalGetDisplayMemoryHandle:
    {
    TInt val = 0;
    TInt passedIn = 0;
    kumemget32(&amp;passedIn, a1, sizeof(TInt));
    
    // Not from a GetAll().
    if (passedIn != -1)    
        {
        r = CreateNewChunkToRepresentDSABuffer(aDeviceNumber,  val);
        }
    else
        {
        r = KErrNone;
        }

    
    kumemput32(a1, &amp;val, sizeof(TInt));
    }
    break;
</codeblock> <p><b>Keeping track of processes that call HAL::Get(EDisplayMemoryHandle) </b> </p> <p>New
DSA clients request the DSA buffer handle rather than the address. After a
process obtains the handle, the DSA buffer is in use for this process until
the handle is closed or the process exits (which implicitly closes the handle). </p> <p>To
track the usage, the LCD Driver creates a new shared chunk every time a process
calls <codeph>HAL::Get(EDisplayMemoryHandle)</codeph>. The LCD Driver then
calls <xref href="GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D.dita#GUID-C6946ECB-775F-3EC2-A56F-78F25B9FBE3D/GUID-BA56B205-60D8-326E-8340-3F78CCEA3DD1"><apiname>Kern::MakeHandleAndOpen()</apiname></xref> to create a user handle
to the shared chunk for the calling process. The LCD Driver closes the kernel-side
handle to the shared chunk and returns the user-side handle to the calling
process. </p> <p>When the user process closes the handle, the shared chunk
is deleted and its deletion DFC runs. The DFC decrements the reference count
of users of the DSA memory. </p> <p>Here is the sequence when a process calls <codeph>HAL::Get(EDisplayMemoryHandle)</codeph> for
the first time: </p> <ol id="GUID-A92B09E9-5E76-5B6C-B281-64A4F4A65467">
<li id="GUID-0CF94725-F9BA-5C92-9429-4206D38040CF"><p>The driver creates a
new shared chunk for this process with a destruction DFC. </p> </li>
<li id="GUID-8521F99F-A890-5F82-9EB0-C0C1E9ABDE5B"><p>The driver creates a
user-side handle to the shared chunk. </p> </li>
<li id="GUID-876EECF6-BC1C-5E57-8555-55D3F5AD01E3"><p>The driver closes its <xref href="GUID-85454082-6734-3F1D-983F-734D4C2AB12D.dita"><apiname>DChunk</apiname></xref> handle
to the shared chunk. </p> </li>
<li id="GUID-F705B1B9-F9F4-56F2-800B-93E4B8FBE75B"><p>The driver returns the
user-side handle to the calling process. </p> </li>
</ol> <p>Here is the sequence when a process closes the DSA buffer: </p> <ol id="GUID-2310D2DC-76BA-5B87-A964-DCA01051CB3E">
<li id="GUID-65CE3E41-D418-59C5-A0FA-A90195A7FE23"><p>The shared chunk destruction
DFC executes and decrements the DSA usage count. </p> </li>
<li id="GUID-96386F96-FF1E-5BD3-B98A-E0B180463AFB"><p>The DFC checks the DSA
usage count and if it is zero, the DFC frees the DSA memory. </p> </li>
</ol> </section>
</conbody><related-links>
<link href="GUID-8C22AF20-EE0E-5AD2-BEFD-FED5A7DBB09B.dita"><linktext>LCD Extension</linktext>
</link>
<link href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita"><linktext>Shared Chunks</linktext>
</link>
<link href="GUID-9AE254D4-AA60-579E-8D9D-F2797106A413.dita"><linktext>User-Side
Hardware Abstraction Technology</linktext></link>
<link href="GUID-4C166A49-31F7-5315-B797-F97DB52600BC.dita"><linktext>Display Driver
Component</linktext></link>
</related-links></concept>